summaryrefslogtreecommitdiffstats
path: root/tinyNET
diff options
context:
space:
mode:
authorMamadou DIOP <bossiel@yahoo.fr>2015-08-17 01:56:35 +0200
committerMamadou DIOP <bossiel@yahoo.fr>2015-08-17 01:56:35 +0200
commit631fffee8a28b1bec5ed1f1d26a20e0135967f99 (patch)
tree74afe3bf3efe15aa82bcd0272b2b0f4d48c2d837 /tinyNET
parent7908865936604036e6f200f1b5e069f8752f3a3a (diff)
downloaddoubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.zip
doubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.tar.gz
-
Diffstat (limited to 'tinyNET')
-rw-r--r--tinyNET/Doxyfile1932
-rw-r--r--tinyNET/Makefile.am104
-rw-r--r--tinyNET/autogen.sh17
-rw-r--r--tinyNET/configure.ac75
-rw-r--r--tinyNET/droid-makefile105
-rw-r--r--tinyNET/footer.html7
-rw-r--r--tinyNET/header.html38
-rw-r--r--tinyNET/installdox.sh1
-rw-r--r--tinyNET/ragel.sh8
-rw-r--r--tinyNET/ragel/tnet_dns_regexp.rl129
-rw-r--r--tinyNET/ragel/tnet_dns_resolvconf.rl157
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp.c331
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp.h121
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_message.c349
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_message.h226
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_option.c326
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_option.h291
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_option_sip.c131
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_option_sip.h62
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6.c269
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6.h128
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_duid.c288
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_duid.h185
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_message.c131
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_message.h143
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_option.c336
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_option.h246
-rw-r--r--tinyNET/src/dns/tnet_dns.c967
-rw-r--r--tinyNET/src/dns/tnet_dns.h125
-rw-r--r--tinyNET/src/dns/tnet_dns_a.c102
-rw-r--r--tinyNET/src/dns/tnet_dns_a.h61
-rw-r--r--tinyNET/src/dns/tnet_dns_aaaa.c104
-rw-r--r--tinyNET/src/dns/tnet_dns_aaaa.h58
-rw-r--r--tinyNET/src/dns/tnet_dns_cname.c93
-rw-r--r--tinyNET/src/dns/tnet_dns_cname.h63
-rw-r--r--tinyNET/src/dns/tnet_dns_message.c359
-rw-r--r--tinyNET/src/dns/tnet_dns_message.h209
-rw-r--r--tinyNET/src/dns/tnet_dns_mx.c95
-rw-r--r--tinyNET/src/dns/tnet_dns_mx.h66
-rw-r--r--tinyNET/src/dns/tnet_dns_naptr.c142
-rw-r--r--tinyNET/src/dns/tnet_dns_naptr.h81
-rw-r--r--tinyNET/src/dns/tnet_dns_ns.c92
-rw-r--r--tinyNET/src/dns/tnet_dns_ns.h63
-rw-r--r--tinyNET/src/dns/tnet_dns_opt.c91
-rw-r--r--tinyNET/src/dns/tnet_dns_opt.h54
-rw-r--r--tinyNET/src/dns/tnet_dns_ptr.c93
-rw-r--r--tinyNET/src/dns/tnet_dns_ptr.h61
-rw-r--r--tinyNET/src/dns/tnet_dns_regexp.c286
-rw-r--r--tinyNET/src/dns/tnet_dns_regexp.h41
-rw-r--r--tinyNET/src/dns/tnet_dns_resolvconf.c314
-rw-r--r--tinyNET/src/dns/tnet_dns_resolvconf.h43
-rw-r--r--tinyNET/src/dns/tnet_dns_rr.c448
-rw-r--r--tinyNET/src/dns/tnet_dns_rr.h171
-rw-r--r--tinyNET/src/dns/tnet_dns_soa.c108
-rw-r--r--tinyNET/src/dns/tnet_dns_soa.h82
-rw-r--r--tinyNET/src/dns/tnet_dns_srv.c133
-rw-r--r--tinyNET/src/dns/tnet_dns_srv.h59
-rw-r--r--tinyNET/src/dns/tnet_dns_txt.c92
-rw-r--r--tinyNET/src/dns/tnet_dns_txt.h61
-rw-r--r--tinyNET/src/ice/tnet_ice.c27
-rw-r--r--tinyNET/src/ice/tnet_ice.h37
-rw-r--r--tinyNET/src/ice/tnet_ice_candidate.c660
-rw-r--r--tinyNET/src/ice/tnet_ice_candidate.h130
-rw-r--r--tinyNET/src/ice/tnet_ice_ctx.c2883
-rw-r--r--tinyNET/src/ice/tnet_ice_ctx.h113
-rw-r--r--tinyNET/src/ice/tnet_ice_event.c85
-rw-r--r--tinyNET/src/ice/tnet_ice_event.h75
-rw-r--r--tinyNET/src/ice/tnet_ice_pair.c988
-rw-r--r--tinyNET/src/ice/tnet_ice_pair.h86
-rw-r--r--tinyNET/src/ice/tnet_ice_utils.c160
-rw-r--r--tinyNET/src/ice/tnet_ice_utils.h42
-rw-r--r--tinyNET/src/stun/AStyle.sh1
-rw-r--r--tinyNET/src/stun/tnet_stun.c440
-rw-r--r--tinyNET/src/stun/tnet_stun.h127
-rw-r--r--tinyNET/src/stun/tnet_stun_attr.c651
-rw-r--r--tinyNET/src/stun/tnet_stun_attr.h81
-rw-r--r--tinyNET/src/stun/tnet_stun_attribute.c1176
-rw-r--r--tinyNET/src/stun/tnet_stun_attribute.h356
-rw-r--r--tinyNET/src/stun/tnet_stun_binding.c127
-rw-r--r--tinyNET/src/stun/tnet_stun_binding.h67
-rw-r--r--tinyNET/src/stun/tnet_stun_message.c495
-rw-r--r--tinyNET/src/stun/tnet_stun_message.h246
-rw-r--r--tinyNET/src/stun/tnet_stun_pkt.c751
-rw-r--r--tinyNET/src/stun/tnet_stun_pkt.h187
-rw-r--r--tinyNET/src/stun/tnet_stun_types.h373
-rw-r--r--tinyNET/src/stun/tnet_stun_utils.c201
-rw-r--r--tinyNET/src/stun/tnet_stun_utils.h45
-rw-r--r--tinyNET/src/tinynet.h59
-rw-r--r--tinyNET/src/tinynet_config.h151
-rw-r--r--tinyNET/src/tls/tnet_dtls.c798
-rw-r--r--tinyNET/src/tls/tnet_dtls.h75
-rw-r--r--tinyNET/src/tls/tnet_tls.c343
-rw-r--r--tinyNET/src/tls/tnet_tls.h64
-rw-r--r--tinyNET/src/tnet.c174
-rw-r--r--tinyNET/src/tnet.h45
-rw-r--r--tinyNET/src/tnet_auth.c30
-rw-r--r--tinyNET/src/tnet_auth.h39
-rw-r--r--tinyNET/src/tnet_endianness.c98
-rw-r--r--tinyNET/src/tnet_endianness.h58
-rw-r--r--tinyNET/src/tnet_hardwares.h64
-rw-r--r--tinyNET/src/tnet_nat.c381
-rw-r--r--tinyNET/src/tnet_nat.h43
-rw-r--r--tinyNET/src/tnet_poll.c109
-rw-r--r--tinyNET/src/tnet_poll.h92
-rw-r--r--tinyNET/src/tnet_proto.h196
-rw-r--r--tinyNET/src/tnet_proxy_node_socks_plugin.c917
-rw-r--r--tinyNET/src/tnet_proxy_node_socks_plugin.h34
-rw-r--r--tinyNET/src/tnet_proxy_plugin.c284
-rw-r--r--tinyNET/src/tnet_proxy_plugin.h125
-rw-r--r--tinyNET/src/tnet_proxydetect.c310
-rw-r--r--tinyNET/src/tnet_proxydetect.h51
-rw-r--r--tinyNET/src/tnet_socket.c339
-rw-r--r--tinyNET/src/tnet_socket.h201
-rw-r--r--tinyNET/src/tnet_transport.c1116
-rw-r--r--tinyNET/src/tnet_transport.h193
-rw-r--r--tinyNET/src/tnet_transport_cfsocket.c1380
-rw-r--r--tinyNET/src/tnet_transport_poll.c913
-rw-r--r--tinyNET/src/tnet_transport_win32.c840
-rw-r--r--tinyNET/src/tnet_types.h184
-rw-r--r--tinyNET/src/tnet_utils.c2187
-rw-r--r--tinyNET/src/tnet_utils.h186
-rw-r--r--tinyNET/src/turn/tnet_turn.c701
-rw-r--r--tinyNET/src/turn/tnet_turn.h175
-rw-r--r--tinyNET/src/turn/tnet_turn_attr.c21
-rw-r--r--tinyNET/src/turn/tnet_turn_attr.h32
-rw-r--r--tinyNET/src/turn/tnet_turn_attribute.c646
-rw-r--r--tinyNET/src/turn/tnet_turn_attribute.h196
-rw-r--r--tinyNET/src/turn/tnet_turn_message.c163
-rw-r--r--tinyNET/src/turn/tnet_turn_message.h75
-rw-r--r--tinyNET/src/turn/tnet_turn_session.c2487
-rw-r--r--tinyNET/src/turn/tnet_turn_session.h103
-rw-r--r--tinyNET/test/droid-makefile28
-rw-r--r--tinyNET/test/stdafx.c23
-rw-r--r--tinyNET/test/stdafx.h35
-rw-r--r--tinyNET/test/targetver.h33
-rw-r--r--tinyNET/test/test.c121
-rw-r--r--tinyNET/test/test.vcproj418
-rw-r--r--tinyNET/test/test_auth.h28
-rw-r--r--tinyNET/test/test_dhcp.h118
-rw-r--r--tinyNET/test/test_dhcp6.h48
-rw-r--r--tinyNET/test/test_dns.h224
-rw-r--r--tinyNET/test/test_ice.h238
-rw-r--r--tinyNET/test/test_ifaces.h99
-rw-r--r--tinyNET/test/test_nat.h211
-rw-r--r--tinyNET/test/test_sockets.h61
-rw-r--r--tinyNET/test/test_stun.h255
-rw-r--r--tinyNET/test/test_tls.h105
-rw-r--r--tinyNET/test/test_transport.h217
-rw-r--r--tinyNET/tinyNET.pc.in16
-rw-r--r--tinyNET/tinyNET.sln51
-rw-r--r--tinyNET/tinyNET.tag18105
-rw-r--r--tinyNET/tinyNET.vcproj732
-rw-r--r--tinyNET/version.rc102
-rw-r--r--tinyNET/winrt/tinyNET.sln39
-rw-r--r--tinyNET/winrt/tinyNET.vcxproj273
-rw-r--r--tinyNET/winrt/tinyNET.vcxproj.filters361
156 files changed, 60182 insertions, 0 deletions
diff --git a/tinyNET/Doxyfile b/tinyNET/Doxyfile
new file mode 100644
index 0000000..786876d
--- /dev/null
+++ b/tinyNET/Doxyfile
@@ -0,0 +1,1932 @@
+# Doxyfile 1.8.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME = tinyNET
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 3.0
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian,
+# Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic,
+# Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
+
+STRIP_FROM_PATH = /Users/dimitri/doxygen/mail/1.5.7/doxywizard/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields or simple typedef fields will be shown
+# inline in the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO (the default), structs, classes, and unions are shown on a separate
+# page (for HTML and Man pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can
+# be an expensive process and often the same symbol appear multiple times in
+# the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too
+# small doxygen will become slower. If the cache is too large, memory is wasted.
+# The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid
+# range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536
+# symbols.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if section-label ... \endif
+# and \cond section-label ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 62
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path. Do not use
+# file names with spaces, bibtex cannot handle them.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.vhd \
+ *.vhdl \
+ *.asm
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = images
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be ignored.
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+# If CLANG_ASSISTED_PARSING is set to YES, then doxygen will use the clang parser
+# for more acurate parsing at the cost of reduced performance. This can be
+# particularly helpful with template rich C++ code for which doxygen's built-in
+# parser lacks the necessairy type information.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified at INPUT and INCLUDE_PATH.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER = header.html
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER = footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
+# SVG. The default value is HTML-CSS, which is slower, but has the best
+# compatibility.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax. However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript
+# pieces of code that will be used on startup of the MathJax code.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript.
+# There are two flavours of web server based search depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools.
+# See the manual for details.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain
+# the search results. Doxygen ships with an example indexer (doxyindexer) and
+# search engine (doxysearch.cgi) which are based on the open source search
+# engine library Xapian. See the manual for configuration details.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will returned the search results when EXTERNAL_SEARCH is enabled.
+# Doxygen ships with an example search engine (doxysearch) which is based on
+# the open source search engine library Xapian. See the manual for configuration
+# details.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
+# of to a relative location where the documentation can be found.
+# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4 will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images
+# or other source files which should be copied to the LaTeX output directory.
+# Note that the files will be copied as-is; there are no commands or markers
+# available.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files
+# that can be used to generate PDF.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it. If left blank docbook will be used as the default path.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES = ../tinySAK/tinySAK.tag=file:///C:/Projects/doubango/branches/2.0/doubango/tinySAK/docs/html
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE = tinyNET.tag
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = NO
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed
+# in the related pages index. If set to NO, only the current project's
+# pages will be listed.
+
+EXTERNAL_PAGES = NO
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# manageable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/tinyNET/Makefile.am b/tinyNET/Makefile.am
new file mode 100644
index 0000000..67a6c74
--- /dev/null
+++ b/tinyNET/Makefile.am
@@ -0,0 +1,104 @@
+lib_LTLIBRARIES = libtinyNET.la
+libtinyNET_la_LIBADD = ../tinySAK/libtinySAK.la
+libtinyNET_la_CPPFLAGS = -I../tinySAK/src -I./src
+
+if USE_SSL
+libtinyNET_la_LIBADD += ${LIBSSL_LIBADD}
+libtinyNET_la_CPPFLAGS += -DHAVE_OPENSSL=1
+endif
+
+if USE_RESOLV
+libtinyNET_la_LIBADD += ${LIBRESOLV_LIBADD}
+endif
+
+libtinyNET_la_SOURCES = \
+ src/tnet.c\
+ src/tnet_auth.c\
+ src/tnet_endianness.c\
+ src/tnet_nat.c\
+ src/tnet_proxy_node_socks_plugin.c\
+ src/tnet_proxy_plugin.c\
+ src/tnet_proxydetect.c\
+ src/tnet_poll.c\
+ src/tnet_socket.c\
+ src/tnet_transport.c\
+ src/tnet_transport_poll.c\
+ src/tnet_utils.c
+
+libtinyNET_la_SOURCES += src/dhcp/tnet_dhcp.c\
+ src/dhcp/tnet_dhcp_message.c\
+ src/dhcp/tnet_dhcp_option.c\
+ src/dhcp/tnet_dhcp_option_sip.c
+
+libtinyNET_la_SOURCES += src/dhcp6/tnet_dhcp6.c\
+ src/dhcp6/tnet_dhcp6_duid.c\
+ src/dhcp6/tnet_dhcp6_message.c\
+ src/dhcp6/tnet_dhcp6_option.c
+
+libtinyNET_la_SOURCES += src/dns/tnet_dns.c\
+ src/dns/tnet_dns_a.c\
+ src/dns/tnet_dns_aaaa.c\
+ src/dns/tnet_dns_cname.c\
+ src/dns/tnet_dns_message.c\
+ src/dns/tnet_dns_mx.c\
+ src/dns/tnet_dns_naptr.c\
+ src/dns/tnet_dns_ns.c\
+ src/dns/tnet_dns_opt.c\
+ src/dns/tnet_dns_ptr.c\
+ src/dns/tnet_dns_regexp.c\
+ src/dns/tnet_dns_resolvconf.c\
+ src/dns/tnet_dns_rr.c\
+ src/dns/tnet_dns_soa.c\
+ src/dns/tnet_dns_srv.c\
+ src/dns/tnet_dns_txt.c
+
+libtinyNET_la_SOURCES += src/ice/tnet_ice_candidate.c\
+ src/ice/tnet_ice_ctx.c\
+ src/ice/tnet_ice_event.c\
+ src/ice/tnet_ice_pair.c\
+ src/ice/tnet_ice_utils.c
+
+libtinyNET_la_SOURCES += src/stun/tnet_stun.c\
+ src/stun/tnet_stun_attr.c\
+ src/stun/tnet_stun_binding.c\
+ src/stun/tnet_stun_pkt.c\
+ src/stun/tnet_stun_utils.c\
+ \
+ src/stun/tnet_stun_attribute.c\
+ src/stun/tnet_stun_message.c
+
+libtinyNET_la_SOURCES += src/tls/tnet_tls.c\
+ src/tls/tnet_dtls.c
+
+libtinyNET_la_SOURCES += src/turn/tnet_turn.c\
+ src/turn/tnet_turn_session.c\
+ \
+ src/turn/tnet_turn_attribute.c\
+ src/turn/tnet_turn_message.c
+
+
+libtinyNET_la_LDFLAGS = $LDFLAGS -no-undefined
+if TARGET_OS_IS_ANDROID
+libtinyNET_la_LDFLAGS += -static
+endif
+
+src_includedir = $(includedir)/tinynet
+src_include_HEADERS = src/*.h
+dhcp_includedir = $(includedir)/tinynet/dhcp
+dhcp_include_HEADERS = src/dhcp/*.h
+dhcp6_includedir = $(includedir)/tinynet/dhcp6
+dhcp6_include_HEADERS = src/dhcp6/*.h
+dns_includedir = $(includedir)/tinynet/dns
+dns_include_HEADERS = src/dns/*.h
+ice_includedir = $(includedir)/tinynet/ice
+ice_include_HEADERS = src/ice/*.h
+stun_includedir = $(includedir)/tinynet/stun
+stun_include_HEADERS = src/stun/*.h
+tls_includedir = $(includedir)/tinynet/tls
+tls_include_HEADERS = src/tls/*.h
+turn_includedir = $(includedir)/tinynet/turn
+turn_include_HEADERS = src/turn/*.h
+
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = tinyNET.pc
diff --git a/tinyNET/autogen.sh b/tinyNET/autogen.sh
new file mode 100644
index 0000000..9c875b0
--- /dev/null
+++ b/tinyNET/autogen.sh
@@ -0,0 +1,17 @@
+echo libtoolize
+libtoolize --copy --force
+
+echo "aclocal"
+aclocal
+
+echo "autoheader"
+autoheader
+
+echo "create NEWS, README, AUTHORS and ChangeLog"
+touch NEWS README AUTHORS ChangeLog
+
+echo "automake"
+automake -a
+
+echo "autoconf"
+autoconf \ No newline at end of file
diff --git a/tinyNET/configure.ac b/tinyNET/configure.ac
new file mode 100644
index 0000000..1fa39b3
--- /dev/null
+++ b/tinyNET/configure.ac
@@ -0,0 +1,75 @@
+AC_PREREQ([2.52])
+AC_INIT(libtinySAK, 0.1, diopmamadou@doubango.org)
+AM_INIT_AUTOMAKE
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_SRCDIR([src/tsk.c])
+
+dnl find suitable C++ compiler
+AC_PROG_CC
+AC_PROG_INSTALL
+
+
+AC_LIBTOOL_WIN32_DLL
+AC_PROG_LIBTOOL
+
+## Are we using Windows?
+#dnl detecting WIN32
+#case "$host" in
+# *cygwin* | *mingw*)
+# AC_DEFINE([WIN32], [], "Using Windows as target os.")
+# ;;
+# *)
+# AC_MSG_RESULT(${host} is not Windows... I will do my best.)
+# ;;
+#esac
+
+# CFLAGS
+CFLAGS="${CFLAGS=}"
+
+#echo Setting up build environment for ${target_cpu}${target_os}
+
+### ENABLE-DEBUG
+AC_MSG_CHECKING(whether to enable debugging)
+debug_default="yes"
+AC_ARG_ENABLE(debug,
+[ --enable-debug[=no/yes] turn on/off debugging
+ [[default=$debug_default]]],
+[ if test "x$enableval" = "xyes" ; then
+ CFLAGS="$CFLAGS -O0 -g3 -DDEBUG"
+ AC_MSG_RESULT(yes)
+ else
+ CFLAGS="$CFLAGS -O3 -NDEBUG"
+ AC_MSG_RESULT(no)
+ fi
+],
+[CFLAGS="$CFLAGS -O0 -g3 -DDEBUG"
+ AC_MSG_RESULT(yes)])
+
+### DEBUG-LEVEL
+AC_ARG_WITH(debug-level,
+[ --with-debug-level[=level] Set debug-level to level [[default=info]]
+ info: informational
+ warn: warnings
+ error [default]: errors
+ fatal: fatal],
+[ if test "x$withval" = "xinfo" ; then
+ AC_DEFINE(DEBUG_LEVEL, DEBUG_LEVEL_INFO, [info debug])
+ AC_MSG_RESULT(info)
+ elif test "x$withval" = "xwarn" ; then
+ AC_DEFINE(DEBUG_LEVEL, DEBUG_LEVEL_INFO, [warn debug])
+ AC_MSG_RESULT(warn)
+ elif test "x$withval" = "xerror" ; then
+ AC_DEFINE(DEBUG_LEVEL, DEBUG_LEVEL_ERROR, [error debug])
+ AC_MSG_RESULT(error)
+ elif test "x$withval" = "xfatal" ; then
+ AC_DEFINE(DEBUG_LEVEL, DEBUG_LEVEL_FATAL, [fatal debug])
+ AC_MSG_RESULT(fatal)
+ fi
+])
+
+
+AC_OUTPUT(
+Makefile
+src/Makefile
+test/Makefile
+) \ No newline at end of file
diff --git a/tinyNET/droid-makefile b/tinyNET/droid-makefile
new file mode 100644
index 0000000..a21924a
--- /dev/null
+++ b/tinyNET/droid-makefile
@@ -0,0 +1,105 @@
+APP := lib$(PROJECT)_$(MARCH).$(EXT)
+
+THIRDPARTIES_INC := ../thirdparties/android/include
+THIRDPARTIES_LIB := ../thirdparties/android/lib
+
+# TLS (Default: enabled)
+ifeq ($(TLS), no)
+ TLS_CFLAGS := -DHAVE_OPENSSL=0
+ TLS_LDFLAGS :=
+else
+ TLS_CFLAGS := -DHAVE_OPENSSL=1
+ TLS_LDFLAGS := -lssl_$(MARCH) -lcrypto_$(MARCH)
+endif
+
+CFLAGS := $(CFLAGS_LIB) $(TLS_CFLAGS) -I$(THIRDPARTIES_INC) -I../tinySAK/src -I./src
+LDFLAGS := $(LDFLAGS_LIB) $(TLS_LDFLAGS) -L$(THIRDPARTIES_LIB) -ltinySAK_$(MARCH)
+
+all: $(APP)
+
+OBJS = \
+ src/tnet.o\
+ src/tnet_auth.o\
+ src/tnet_endianness.o\
+ src/tnet_nat.o\
+ src/tnet_poll.o\
+ src/tnet_socket.o\
+ src/tnet_transport.o\
+ src/tnet_transport_poll.o\
+ src/tnet_utils.o
+ ###################
+ ## DHCP
+ ###################
+OBJS += src/dhcp/tnet_dhcp.o\
+ src/dhcp/tnet_dhcp_message.o\
+ src/dhcp/tnet_dhcp_option.o\
+ src/dhcp/tnet_dhcp_option_sip.o
+ ###################
+ ## DHCPv6
+ ###################
+OBJS += src/dhcp6/tnet_dhcp6.o\
+ src/dhcp6/tnet_dhcp6_duid.o\
+ src/dhcp6/tnet_dhcp6_message.o\
+ src/dhcp6/tnet_dhcp6_option.o
+ ###################
+ ## DNS
+ ###################
+OBJS += src/dns/tnet_dns.o\
+ src/dns/tnet_dns_a.o\
+ src/dns/tnet_dns_aaaa.o\
+ src/dns/tnet_dns_cname.o\
+ src/dns/tnet_dns_message.o\
+ src/dns/tnet_dns_mx.o\
+ src/dns/tnet_dns_naptr.o\
+ src/dns/tnet_dns_ns.o\
+ src/dns/tnet_dns_opt.o\
+ src/dns/tnet_dns_ptr.o\
+ src/dns/tnet_dns_regexp.o\
+ src/dns/tnet_dns_resolvconf.o\
+ src/dns/tnet_dns_rr.o\
+ src/dns/tnet_dns_soa.o\
+ src/dns/tnet_dns_srv.o\
+ src/dns/tnet_dns_txt.o
+ ###################
+ ## ICE
+ ###################
+OBJS += src/ice/tnet_ice_candidate.o \
+ src/ice/tnet_ice_ctx.o \
+ src/ice/tnet_ice_event.o \
+ src/ice/tnet_ice_pair.o \
+ src/ice/tnet_ice_utils.o
+ ###################
+ ## STUN
+ ###################
+OBJS += src/stun/tnet_stun.o\
+ src/stun/tnet_stun_attribute.o\
+ src/stun/tnet_stun_message.o
+ ###################
+ ## TLS / DTLS
+ ###################
+OBJS += src/tls/tnet_tls.o\
+ src/tls/tnet_dtls.o
+ ###################
+ ## TURN
+ ###################
+OBJS += src/turn/tnet_turn.o\
+ src/turn/tnet_turn_attribute.o\
+ src/turn/tnet_turn_message.o
+
+$(APP): $(OBJS)
+ifeq ($(EXT), a)
+ $(AR) rcs $@ $^
+else
+ $(CC) $(LDFLAGS) -o $@ $^
+endif
+
+%.o: %.c
+ $(CC) -c $(INCLUDE) $(CFLAGS) $< -o $@
+
+install: $(APP)
+ $(ANDROID_SDK_ROOT)/tools/adb remount
+ $(ANDROID_SDK_ROOT)/tools/adb push $(APP) $(LIB_DIR)/$(APP)
+ $(ANDROID_SDK_ROOT)/tools/adb shell chmod 777 $(LIB_DIR)/$(APP)
+
+clean:
+ @rm -f $(OBJS) $(APP) \ No newline at end of file
diff --git a/tinyNET/footer.html b/tinyNET/footer.html
new file mode 100644
index 0000000..fbe1338
--- /dev/null
+++ b/tinyNET/footer.html
@@ -0,0 +1,7 @@
+<html>
+<head></head>
+<body>
+<hr>
+<b>doubango project - tinyNET 1.0</b> - Copyright (C) 2009-2010 Mamadou DIOP. All rights reserved. Licensed under the terms of the GNU General Public License v3.
+</body>
+</html> \ No newline at end of file
diff --git a/tinyNET/header.html b/tinyNET/header.html
new file mode 100644
index 0000000..b7bb298
--- /dev/null
+++ b/tinyNET/header.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>doubango - tinyNET</title>
+ <link rel="stylesheet" href="http://www.doubango.org/css.css" type="text/css" />
+ <link href="tabs.css" rel="stylesheet" type="text/css"/>
+ <link href="doxygen.css" rel="stylesheet" type="text/css"/>
+ <meta name="Keywords" content="doubango, 3GPP IMS/LTE framework, open source, SIP, RFC 3261, 3GPP TS 24.229, VoIP, MMTel, IPTV, 4G, LTE, XCAP, MSRP, IPSec, SigComp, One Voice " />
+ <meta name="Description" content="cross-platform and open source 3GPP IMS/LTE framework for embedded devices such as Android, Symbian, iPhone, Windows Mobile or uLinux." />
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+
+<style type="text/css">
+/*<![CDATA[*/
+ p.c1 {text-align: center;}
+/*]]>*/
+</style>
+</head>
+
+<body>
+ <div id="left">
+ <div id="border">
+ <div id="logo">
+ <p class="companyname">
+ tinyNET</p>
+ </div>
+ <div id="menu">
+ <a href="/index.html" title="Homepage">Home</a> <a href="/gettingstarted.html" title="Getting Started">
+ Getting Started</a> <a href="http://code.google.com/p/doubango/source/checkout" title="Source Code"
+ target="_blank">Source Code</a> <a href="/apiref.html" title="API Reference">API Reference</a> <a href="contact.html" title="Contact">
+ Contact</a>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
+
diff --git a/tinyNET/installdox.sh b/tinyNET/installdox.sh
new file mode 100644
index 0000000..2517e03
--- /dev/null
+++ b/tinyNET/installdox.sh
@@ -0,0 +1 @@
+docs/html/installdox -l tinySAK.tag@http://doubango.org/API/tinySAK docs/html/*.html \ No newline at end of file
diff --git a/tinyNET/ragel.sh b/tinyNET/ragel.sh
new file mode 100644
index 0000000..d8b9e31
--- /dev/null
+++ b/tinyNET/ragel.sh
@@ -0,0 +1,8 @@
+# Ragel generator
+# For more information about Ragel: http://www.complang.org/ragel/
+
+export OPTIONS="-C -L -T0"
+#export OPTIONS="-C -L -G2"
+
+ragel.exe $OPTIONS -o ./src/dns/tnet_dns_regexp.c ./ragel/tnet_dns_regexp.rl
+ragel.exe $OPTIONS -o ./src/dns/tnet_dns_resolvconf.c ./ragel/tnet_dns_resolvconf.rl
diff --git a/tinyNET/ragel/tnet_dns_regexp.rl b/tinyNET/ragel/tnet_dns_regexp.rl
new file mode 100644
index 0000000..0c45be4
--- /dev/null
+++ b/tinyNET/ragel/tnet_dns_regexp.rl
@@ -0,0 +1,129 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_regexp.c
+ * @brief DNS Regex parser for NAPTR RR.
+ */
+#include "tnet_dns_regexp.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_ragel_state.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+/* === Ragel state machine === */
+%%{
+ machine tdns_machine_regexp;
+
+ action tag {
+ tag_start = p;
+ }
+
+ action parse_prefix {
+ TSK_PARSER_SET_STRING(prefix);
+ }
+
+ action cat_any{
+ int len = (int)(p - tag_start);
+ if (len) {
+ tsk_strncat(&ret, tag_start, len);
+ }
+ }
+
+ action cat_group {
+ if (prefix) {
+ int prefixlen = (tsk_size_t)tsk_strlen(prefix);
+ tsk_strncat(&ret, e164num + prefixlen, (e164len - prefixlen));
+ }
+ }
+
+ # http://www.itu.int/itudoc/itu-t/workshop/enum/012_pp7.ppt
+ # The format is like this: !<regexp>!<string>!
+ # * 1. Match <regexp> on the original E.164 number
+ # * 2. Apply rewrite rule <string>
+ # * \n in <string> is replaced with group number 'n' in <regexp>
+ #
+
+ regexp = (".*") | ("\\"? <:any*>tag %parse_prefix :>"(.*)");
+ group = "\\" digit;
+ string = (any -- "\\")*>tag %cat_any (group >tag %cat_group)? (any -- "\\")*>tag %cat_any;
+
+ # Supported regexp --> !^.*$! or !^+1800(.*)! where "1800" is called the prefix
+ main := "!^"<: regexp :> "$!" <: string :>"!" "i"?;
+}%%
+
+/**
+* Apply @a regexp to @a e164num.
+* @param e164num Original E.164 number supplied by the user (only digits or '+' are accepted).
+* @param regexp A <character-string> containing a substitution expression that is
+* applied to the original string held by the client in order to
+* construct the next domain name to lookup. Example: "!^.*$!sip:bob@doubango.org!i".
+* @retval The final Internet address. It's up to the caller to free the string.
+*/
+char* tnet_dns_regex_parse(const char* e164num, const char* regexp)
+{
+ char* ret = tsk_null;
+ char* prefix = tsk_null;
+ const char* tag_start;
+ tsk_size_t e164len;
+
+ // Ragel
+ int cs = 0;
+ const char *p = tag_start = regexp;
+ const char *pe;
+ const char *eof;
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+ %%write data;
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+ (void)(eof);
+ (void)(tdns_machine_regexp_first_final);
+ (void)(tdns_machine_regexp_error);
+ (void)(tdns_machine_regexp_en_main);
+
+ if (!e164num) {
+ goto bail;
+ }
+
+ if (!regexp) {
+ ret = tsk_strdup(e164num);
+ goto bail;
+ }
+
+ e164len = (tsk_size_t)tsk_strlen(e164num);
+ pe = p + tsk_strlen(regexp);
+ eof = pe;
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+ %%write init;
+ %%write exec;
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+
+ if (cs < %%{ write first_final; }%% ){
+ TSK_DEBUG_ERROR("regexp substitition failed.");
+ TSK_FREE(ret);
+ }
+
+bail:
+ TSK_FREE(prefix);
+
+ return ret;
+}
diff --git a/tinyNET/ragel/tnet_dns_resolvconf.rl b/tinyNET/ragel/tnet_dns_resolvconf.rl
new file mode 100644
index 0000000..b81207c
--- /dev/null
+++ b/tinyNET/ragel/tnet_dns_resolvconf.rl
@@ -0,0 +1,157 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_resolvconf.c
+ * @brief Parser for "/etc/resolv.conf" file to retrive DNS servers.
+ */
+#include "tnet_dns_resolvconf.h"
+
+#include "tnet_utils.h"
+
+#include "dns/tnet_dns.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_ragel_state.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+
+/* === Ragel state machine === */
+%%{
+ machine tdns_machine_resolvconf;
+
+ action tag{
+ tag_start = p;
+ }
+
+ action add_dns{
+ int len = (int)(p - tag_start);
+ if(len && len<=sizeof(ip)){
+ tnet_address_t *address;
+ memset(ip, '\0', sizeof(ip));
+ memcpy(ip, tag_start, len);
+ TSK_DEBUG_INFO("Adding DNS server = %s:%d", ip, TNET_DNS_SERVER_PORT_DEFAULT);
+
+ address = tnet_address_create(ip);
+ address->family = tnet_get_family(ip, TNET_DNS_SERVER_PORT_DEFAULT);
+ address->dnsserver = 1;
+ tsk_list_push_ascending_data(servers, (void**)&address);
+ }
+ }
+
+ SP = " ";
+ LF = "\n";
+ CR = "\r";
+ CRLF = CR LF;
+ ENDL = (LF | CR | CRLF);
+
+ o_name = any+;
+ o_value = any+;
+
+ COMMENT = SP*<: ("#" | ";") any*;
+ OPTION_ANY = SP*<: o_name :>SP+<: o_value :>SP*;
+ OPTION_DNS = SP*<: "nameserver"i :>SP+<: o_value>tag %add_dns :>SP*;
+ LINE = (OPTION_DNS)@100 | (OPTION_ANY)@0 | (COMMENT)@50;
+
+ main := ((LINE :>ENDL) | ENDL)* %3 any* %2;
+}%%
+
+/** Gets list of DNS servers from a conf file.
+* @param path Path of the conf file from which to retrieve the DNS servers.
+* should be @a "/etc/resolv.conf". You can adjust the value by modifying @ref TNET_RESOLV_CONF_PATH.<br>
+* If you are using <b>Android</b> and the resolv.conf file is missing, then run the following line in a command window: <br>
+* <i>ln -s /private/var/run/resolv.conf /etc/resolv.conf</i><br> If this fails, then try to manually add the file.
+* @retval List of DNS servers.
+*/
+tnet_addresses_L_t * tnet_dns_resolvconf_parse(const char* path)
+{
+ tnet_addresses_L_t* servers = tsk_null;
+ tnet_ip_t ip;
+ const char* fullpath = path;
+ const char* tag_start = tsk_null;
+ FILE* fd;
+ char* buf = tsk_null;
+
+ // Ragel
+ int cs = 0;
+ const char *p;
+ const char *pe;
+ const char *eof;
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+ %%write data;
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+ (void)(eof);
+ (void)(tdns_machine_resolvconf_first_final);
+ (void)(tdns_machine_resolvconf_error);
+ (void)(tdns_machine_resolvconf_en_main);
+
+ if(tsk_strnullORempty(fullpath)){
+ fullpath = TNET_RESOLV_CONF_PATH;
+ }
+
+ /* Open the file and read all data */
+ if((fd = fopen(fullpath, "r"))){
+ long len;
+ fseek(fd, 0L, SEEK_END);
+ len = ftell(fd);
+ fseek(fd, 0L, SEEK_SET);
+ if (!(buf = (char*)tsk_calloc(len + 1, 1))) {
+ TSK_DEBUG_ERROR("Failed to allocate buffer with size = %ld", (len + 1));
+ goto bail;
+ }
+ fread(buf, 1, len, fd);
+ p = &buf[0];
+ pe = p + len + 1/*hack*/;
+ eof = pe;
+ fclose(fd);
+
+ buf[len] = '\n'; // hack to have perfect lines
+
+ servers = tsk_list_create();
+ }
+ else {
+#if ANDROID || defined(__APPLE__) /* TARGET_OS_IPHONE not defined for bsd libraries */
+ TSK_DEBUG_INFO("Failed to open [%s]. But don't panic, we have detected that you are using Google Android/iOS Systems.\n"
+ "You should look at the Progammer's Guide for more information.\n If you are not using DNS functions, don't worry about this warning.",
+ fullpath);
+#else
+ TSK_DEBUG_ERROR("Failed to open %s.", fullpath);
+#endif
+ goto bail;
+ }
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+ %%write init;
+ %%write exec;
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+
+ if (cs < %%{ write first_final; }%% ) {
+ TSK_DEBUG_ERROR("Failed to parse %s.", fullpath);
+ TSK_OBJECT_SAFE_FREE(servers);
+ }
+
+bail:
+ TSK_FREE(buf);
+ return servers;
+}
+
+
diff --git a/tinyNET/src/dhcp/tnet_dhcp.c b/tinyNET/src/dhcp/tnet_dhcp.c
new file mode 100644
index 0000000..efd57c5
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp.c
@@ -0,0 +1,331 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp.c
+ * @brief DHCP/BOOTP (RFC 2131 - Dynamic Host Configuration Protocol) utilities function for P-CSCF discovery(RFC 3319 and 3361).
+ * Also implement: RFC 3315, 3118, 3319, 3825 (Geoconf), 4676 (Civic Addresses Configuration Information) ...
+ */
+#include "tnet_dhcp.h"
+
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_thread.h"
+#include "tsk_memory.h"
+#include "tsk_time.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+// Useful link: http://support.microsoft.com/?scid=kb%3Ben-us%3B169289&x=21&y=14
+// Another one: http://www.iana.org/assignments/bootp-dhcp-parameters/
+// Another one: http://www.slideshare.net/raini/DHCP-Presentation-v102
+// RFC 3319 Dynamic Host Configuration Protocol (DHCPv6) Options for Session Initiation Protocol (SIP) Servers
+// RFC 3361 Dynamic Host Configuration Protocol (DHCP-for-IPv4) Option for Session Initiation Protocol (SIP) Servers
+
+/**@defgroup tnet_dhcp_group DHCPv4/BOOTP (RFC 2131) implementation.
+*/
+
+/**@ingroup tnet_dhcp_group
+* Creates new DHCPv4 context.
+*/
+tnet_dhcp_ctx_t* tnet_dhcp_ctx_create()
+{
+ return tsk_object_new(tnet_dhcp_ctx_def_t);
+}
+
+/**@ingroup tnet_dhcp_group
+* Creates new DHCPv4 parameters.
+*/
+tnet_dhcp_params_t* tnet_dhcp_params_create()
+{
+ return tsk_object_new(tnet_dhcp_params_def_t);
+}
+
+/* FIXME: USE retransmission mech (*2*2...)
+*/
+/**@ingroup tnet_dhcp_group
+*/
+tnet_dhcp_reply_t* tnet_dhcp_send_request(tnet_dhcp_ctx_t* ctx, tnet_dhcp_request_t* request)
+{
+ tsk_buffer_t *output;
+ tnet_dhcp_reply_t* reply = tsk_null;
+ int ret;
+ struct timeval tv;
+ fd_set set;
+ uint64_t timeout = 0;
+ tsk_list_item_t *item;
+ const tnet_interface_t *iface;
+
+ tnet_socket_t *localsocket4 = tsk_null;
+ struct sockaddr_storage server;
+
+ if (!ctx || !request){
+ goto bail;
+ }
+
+ localsocket4 = tnet_socket_create(TNET_SOCKET_HOST_ANY, ctx->port_client, tnet_socket_type_udp_ipv4);
+ if (!TNET_SOCKET_IS_VALID(localsocket4)){
+ TSK_DEBUG_ERROR("Failed to create/bind DHCP client socket.");
+ goto bail;
+ }
+
+ /* Always wait for 200ms before retransmission */
+ tv.tv_sec = 0;
+ tv.tv_usec = (200 * 1000);
+
+ if (tnet_sockaddr_init("255.255.255.255", ctx->server_port, tnet_socket_type_udp_ipv4, &server)){
+ TNET_PRINT_LAST_ERROR("Failed to initialize the DHCP server address");
+ goto bail;
+ }
+
+ /* ENABLE BROADCASTING */
+ {
+#if defined(SOLARIS)
+ char yes = '1';
+#else
+ int yes = 1;
+#endif
+ if (setsockopt(localsocket4->fd, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(int))){
+ TNET_PRINT_LAST_ERROR("Failed to enable broadcast option");
+ goto bail;
+ }
+ }
+
+ /* Set timeout */
+ timeout = tsk_time_now() + ctx->timeout;
+
+ do
+ {
+ /* RFC 2131 - 3.6 Use of DHCP in clients with multiple interfaces
+ A client with multiple network interfaces must use DHCP through each
+ interface independently to obtain configuration information
+ parameters for those separate interfaces.
+ */
+
+ tsk_list_foreach(item, ctx->interfaces){
+ iface = item->data;
+
+ /* Set FD */
+ FD_ZERO(&set);
+ FD_SET(localsocket4->fd, &set);
+
+ /* ciaddr */
+ if (request->type == dhcp_type_inform){
+ struct sockaddr_storage ss;
+ if (!tnet_getsockname(localsocket4->fd, &ss)){
+ uint32_t addr = (uint32_t)tnet_htonl_2(&((struct sockaddr_in*)&ss)->sin_addr);
+ memcpy(&request->ciaddr, &addr, 4);
+ }
+ }
+
+ /* chaddr */
+ memset(request->chaddr, 0, sizeof(request->chaddr));
+ request->hlen = (uint8_t)(iface->mac_address_length > sizeof(request->chaddr) ? sizeof(request->chaddr) : iface->mac_address_length);
+ memcpy(request->chaddr, iface->mac_address, request->hlen);
+
+ /* Serialize and send to the server. */
+ if (!(output = tnet_dhcp_message_serialize(ctx, request))){
+ TSK_DEBUG_ERROR("Failed to serialize the DHCP message.");
+ goto next_iface;
+ }
+ /* Send the request to the DHCP server */
+ if ((ret = tnet_sockfd_sendto(localsocket4->fd, (const struct sockaddr*)&server, output->data, output->size)) < 0){
+ TNET_PRINT_LAST_ERROR("Failed to send DHCP request");
+
+ tsk_thread_sleep(150); // wait 150ms before trying the next iface.
+ goto next_iface;
+ }
+ /* wait for response */
+ if ((ret = select(localsocket4->fd + 1, &set, NULL, NULL, &tv)) < 0){ /* Error */
+ TNET_PRINT_LAST_ERROR("select have failed.");
+ tsk_thread_sleep(150); // wait 150ms before trying the next iface.
+ goto next_iface;
+ }
+ else if (ret == 0)
+ { /* timeout ==> do nothing */
+ }
+ else
+ { /* there is data to read */
+ unsigned int len = 0;
+ void* data = tsk_null;
+
+ /* Check how how many bytes are pending */
+ if ((ret = tnet_ioctlt(localsocket4->fd, FIONREAD, &len)) < 0){
+ goto next_iface;
+ }
+
+ /* Receive pending data */
+ data = tsk_calloc(len, sizeof(uint8_t));
+ if ((ret = tnet_sockfd_recv(localsocket4->fd, data, len, 0)) < 0){
+ TSK_FREE(data);
+
+ TNET_PRINT_LAST_ERROR("Failed to receive DHCP dgrams.");
+ goto next_iface;
+ }
+
+ /* Parse the incoming response. */
+ reply = tnet_dhcp_message_deserialize(ctx, data, (tsk_size_t)ret);
+ TSK_FREE(data);
+
+ if (reply)
+ { /* response successfuly parsed */
+ if (request->xid != reply->xid)
+ { /* Not same transaction id ==> continue*/
+ TSK_OBJECT_SAFE_FREE(reply);
+ }
+ }
+ }
+
+ next_iface:
+ TSK_OBJECT_SAFE_FREE(output);
+ if (reply){
+ goto bail;
+ }
+ }
+ //break;//FIXME
+ } while (timeout > tsk_time_epoch());
+
+bail:
+ TSK_OBJECT_SAFE_FREE(localsocket4);
+
+ return reply;
+}
+
+/**@ingroup tnet_dhcp_group
+*/
+tnet_dhcp_reply_t* tnet_dhcp_query(tnet_dhcp_ctx_t* ctx, tnet_dhcp_message_type_t type, tnet_dhcp_params_t* params)
+{
+ tnet_dhcp_reply_t* reply = tsk_null;
+ tnet_dhcp_request_t* request = tnet_dhcp_request_create();
+
+ if (!ctx || !params || !request){
+ goto bail;
+ }
+
+ request->type = type;
+ tnet_dhcp_message_add_codes(request, params->codes, params->codes_count);
+
+ reply = tnet_dhcp_send_request(ctx, request);
+
+bail:
+ TSK_OBJECT_SAFE_FREE(request);
+
+ return reply;
+}
+
+/**@ingroup tnet_dhcp_group
+*/
+int tnet_dhcp_params_add_code(tnet_dhcp_params_t* params, tnet_dhcp_option_code_t code)
+{
+ if (params){
+ if (params->codes_count < TNET_DHCP_MAX_CODES){
+ unsigned i;
+ for (i = 0; i < params->codes_count; i++){
+ if (params->codes[i] == code){
+ return -3;
+ }
+ }
+ params->codes[params->codes_count++] = code;
+ }
+ else return -2;
+ }
+ return -1;
+}
+
+
+
+//=================================================================================================
+// [[DHCP CONTEXT]] object definition
+//
+static tsk_object_t* tnet_dhcp_ctx_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_ctx_t *ctx = self;
+ if (ctx){
+ tnet_host_t host;
+
+ ctx->vendor_id = tsk_strdup(TNET_DHCP_VENDOR_ID_DEFAULT);
+ if (!tnet_gethostname(&host)){
+ ctx->hostname = tsk_strndup(host, tsk_strlen(host));
+ }
+ ctx->timeout = TNET_DHCP_TIMEOUT_DEFAULT;
+ ctx->max_msg_size = TNET_DHCP_MAX_MSG_SIZE;
+ ctx->port_client = TNET_DHCP_CLIENT_PORT;
+ ctx->server_port = TNET_DHCP_SERVER_PORT;
+ ctx->interfaces = tnet_get_interfaces();
+
+ if (!ctx->interfaces || TSK_LIST_IS_EMPTY(ctx->interfaces)){
+ TSK_DEBUG_ERROR("Failed to retrieve network interfaces.");
+ }
+
+ tsk_safeobj_init(ctx);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_ctx_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_ctx_t *ctx = self;
+ if (ctx){
+ tsk_safeobj_deinit(ctx);
+
+ TSK_FREE(ctx->vendor_id);
+ TSK_FREE(ctx->hostname);
+
+ TSK_OBJECT_SAFE_FREE(ctx->interfaces);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_ctx_def_s =
+{
+ sizeof(tnet_dhcp_ctx_t),
+ tnet_dhcp_ctx_ctor,
+ tnet_dhcp_ctx_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_ctx_def_t = &tnet_dhcp_ctx_def_s;
+
+//=================================================================================================
+// [[DHCP PARAMS]] object definition
+//
+static tsk_object_t* tnet_dhcp_params_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_params_t *params = self;
+ if (params){
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_params_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_params_t *params = self;
+ if (params){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_params_def_s =
+{
+ sizeof(tnet_dhcp_params_t),
+ tnet_dhcp_params_ctor,
+ tnet_dhcp_params_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_params_def_t = &tnet_dhcp_params_def_s;
diff --git a/tinyNET/src/dhcp/tnet_dhcp.h b/tinyNET/src/dhcp/tnet_dhcp.h
new file mode 100644
index 0000000..9572641
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp.h
@@ -0,0 +1,121 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp.h
+ * @brief DHCP (RFC 2131 - Dynamic Host Configuration Protocol) utilities function for P-CSCF discovery(RFC 3319 and 3361)
+ * Also implement: RFC 3315, 3118, 3319, 3825 (Geoconf), 4676 (Civic Addresses Configuration Information)...
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef TNET_DHCP_H
+#define TNET_DHCP_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp_message.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_object.h"
+#include "tsk_safeobj.h"
+
+TNET_BEGIN_DECLS
+
+/**@ingroup tnet_dhcp_group
+* Default timeout (in milliseconds) value for DHCP requests.
+*/
+#define TNET_DHCP_TIMEOUT_DEFAULT 2000
+
+/**@ingroup tnet_dhcp_group
+* Local port(client) to bind to for incoming DHCP messages as per RFC 2131 subclause 4.1. */
+#define TNET_DHCP_CLIENT_PORT 68
+/**@ingroup tnet_dhcp_group
+* Destination port(Server) for outgoing DHCP messages as per RFC 2131 subclause 4.1. */
+#define TNET_DHCP_SERVER_PORT 67
+
+/**@ingroup tnet_dhcp_group
+* @def TNET_DHCP_VENDOR_ID_DEFAULT
+*/
+/**@ingroup tnet_dhcp_group
+* @def TNET_DHCP_MAX_CODES
+*/
+/**@ingroup tnet_dhcp_group
+* @def TNET_DHCP_MAX_MSG_SIZE
+*/
+#define TNET_DHCP_VENDOR_ID_DEFAULT "doubango/v0.0.0"
+#define TNET_DHCP_MAX_CODES 20
+#define TNET_DHCP_MAX_MSG_SIZE 1500
+
+/**@ingroup tnet_dhcp_group
+* Parameter Request List (55)
+*/
+typedef struct tnet_dhcp_params_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_dhcp_option_code_t codes[TNET_DHCP_MAX_CODES];
+ unsigned codes_count;
+}
+tnet_dhcp_params_t;
+
+/**@ingroup tnet_dhcp_group
+*/
+typedef struct tnet_dhcp_ctx_s
+{
+ TSK_DECLARE_OBJECT;
+
+ char* vendor_id;
+ char* hostname;
+ uint16_t max_msg_size; /**< Option code 57. */
+
+ uint64_t timeout;
+
+ tnet_port_t port_client; /**< Local port to bind to for incloming DHCP messages. Default: 68 */
+ tnet_port_t server_port; /**< Destination port for outgoing DHCP messages. Default: 64 */
+ tnet_interfaces_L_t *interfaces;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_dhcp_ctx_t;
+
+
+TINYNET_API tnet_dhcp_reply_t* tnet_dhcp_query(tnet_dhcp_ctx_t* ctx, tnet_dhcp_message_type_t type, tnet_dhcp_params_t* params);
+#define tnet_dhcp_query_discover(ctx, params) tnet_dhcp_query(ctx, dhcp_type_discover, params)
+#define tnet_dhcp_query_request(ctx, params) tnet_dhcp_query(ctx, dhcp_type_request, params)
+#define tnet_dhcp_query_decline(ctx, params) tnet_dhcp_query(ctx, dhcp_type_decline, params)
+#define tnet_dhcp_query_release(ctx, params) tnet_dhcp_query(ctx, dhcp_type_release, params)
+#define tnet_dhcp_query_inform(ctx, params) tnet_dhcp_query(ctx, dhcp_type_inform, params)
+
+TINYNET_API int tnet_dhcp_params_add_code(tnet_dhcp_params_t* params, tnet_dhcp_option_code_t code);
+
+
+TINYNET_API tnet_dhcp_ctx_t* tnet_dhcp_ctx_create();
+TINYNET_API tnet_dhcp_params_t* tnet_dhcp_params_create();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_ctx_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_params_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP_H */
diff --git a/tinyNET/src/dhcp/tnet_dhcp_message.c b/tinyNET/src/dhcp/tnet_dhcp_message.c
new file mode 100644
index 0000000..005327d
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_message.c
@@ -0,0 +1,349 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp_message.c
+ * @brief DHCP Message as per RFC 2131 subclause 2.
+ */
+#include "tnet_dhcp_message.h"
+#include "tnet_dhcp.h"
+
+#include "../tnet_utils.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_time.h"
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+tnet_dhcp_message_t* tnet_dhcp_message_create(tnet_dhcp_message_op_t opcode)
+{
+ return tsk_object_new(tnet_dhcp_message_def_t, opcode);
+}
+
+tnet_dhcp_request_t* tnet_dhcp_request_create()
+{
+ return tnet_dhcp_message_create(dhcp_op_bootrequest);
+}
+
+tnet_dhcp_message_t* tnet_dhcp_reply_create()
+{
+ return tnet_dhcp_message_create(dhcp_op_bootreply);
+}
+
+tsk_buffer_t* tnet_dhcp_message_serialize(const tnet_dhcp_ctx_t *ctx, const tnet_dhcp_message_t *message)
+{
+ tsk_buffer_t* output = 0;
+ uint8_t _1byte;
+ uint16_t _2bytes;
+ uint32_t _4bytes;
+
+ /* Check message validity */
+ if (!message){
+ goto bail;
+ }
+
+ output = tsk_buffer_create_null();
+
+ /*== OP HTYPE HLEN HOPS */
+ _4bytes = (((uint32_t)(message->op)) << 24) |
+ (((uint32_t)(message->htype)) << 16) |
+ (((uint16_t)(message->hlen)) << 8) | message->hops;
+ _4bytes = (uint32_t)tnet_ntohl(_4bytes);
+ tsk_buffer_append(output, &(_4bytes), 4);
+
+ /*== XID */
+ _4bytes = (uint32_t)tnet_ntohl(message->xid);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ /*== SECS */
+ _2bytes = tnet_ntohs(message->secs);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /*== FLAGS */
+ _2bytes = tnet_ntohs(message->flags);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /*== CIADDR */
+ _4bytes = (uint32_t)tnet_ntohl(message->ciaddr);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ /*== YIADDR */
+ _4bytes = (uint32_t)tnet_ntohl(message->yiaddr);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ /*== SIADDR */
+ _4bytes = (uint32_t)tnet_ntohl(message->siaddr);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ /*== GIADDR */
+ _4bytes = (uint32_t)tnet_ntohl(message->giaddr);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ /*== CHADDR */
+ tsk_buffer_append(output, message->chaddr, sizeof(message->chaddr));
+ /*== sname (unused) */
+ tsk_buffer_append(output, message->sname, sizeof(message->sname));
+ /*== file (unused) */
+ tsk_buffer_append(output, message->file, sizeof(message->file));
+ /*== Magic Cookie */
+ _4bytes = (uint32_t)tnet_ntohl(TNET_DHCP_MAGIC_COOKIE);
+ tsk_buffer_append(output, &(_4bytes), 4);
+
+ /*== Message Type (option 53)
+ */
+ tnet_dhcp_option_serializeex(dhcp_code_DHCP_Msg_Type, 1, &message->type, output);
+
+ /*== Client Identifier (option 61) ==> RFC 2132 - 9.14. Client-identifier
+ Code Len Type Client-Identifier
+ +-----+-----+-----+-----+-----+---
+ | 61 | n | t1 | i1 | i2 | ...
+ +-----+-----+-----+-----+-----+---
+ */
+ if (message->hlen){
+ uint8_t client_id[17]; // 16 /*sizeof(chaddr)*/+ 1/*htype*/
+ /*if(client_id)*/{
+ client_id[0] = message->htype;
+ memcpy(&client_id[1], message->chaddr, message->hlen);
+ tnet_dhcp_option_serializeex(dhcp_code_Client_Id, (message->hlen + 1), client_id, output);
+ }
+ }
+ /*== Host name(10) ==> RFC 2132 - 3.14. Host Name Option
+ Code Len Host Name
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 12 | n | h1 | h2 | h3 | h4 | h5 | h6 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ */
+ if (TNET_DHCP_MESSAGE_IS_REQUEST(message) && ctx->hostname){
+ tnet_dhcp_option_serializeex(dhcp_code_Hostname, (uint8_t)tsk_strlen(ctx->hostname), ctx->hostname, output);
+ }
+ /*== Vendor classId(60) ==> RFC 2132 - 9.13. Vendor class identifier
+ Code Len Vendor class Identifier
+ +-----+-----+-----+-----+---
+ | 60 | n | i1 | i2 | ...
+ +-----+-----+-----+-----+---
+ */
+ if (TNET_DHCP_MESSAGE_IS_REQUEST(message) && ctx->vendor_id){
+ tnet_dhcp_option_serializeex(dhcp_code_Class_Id, (uint8_t)tsk_strlen(ctx->vendor_id), ctx->vendor_id, output);
+ }
+
+ /*== RFC 2132 - 9.10. Maximum DHCP Message Size (57)
+ Code Len Length
+ +-----+-----+-----+-----+
+ | 57 | 2 | l1 | l2 |
+ +-----+-----+-----+-----+
+ */
+ if (TNET_DHCP_MESSAGE_IS_REQUEST(message) && ctx->max_msg_size){
+ _2bytes = tnet_ntohs(ctx->max_msg_size);
+ tnet_dhcp_option_serializeex(dhcp_code_DHCP_Max_Msg_Size, 2, &_2bytes, output);
+ }
+
+ /*== DHCP Options
+ */
+ {
+ tsk_list_item_t *item;
+ tnet_dhcp_option_t* option;
+ tsk_list_foreach(item, message->options)
+ {
+ option = (tnet_dhcp_option_t*)item->data;
+ if (tnet_dhcp_option_serialize(option, output)){
+ TSK_DEBUG_WARN("Failed to serialize DHCP OPTION (%u)", option->code);
+ }
+ }
+ }
+
+ /* RFC 2131 - 4.1 Constructing and sending DHCP messages
+ The last option must always be the 'end' option.
+ */
+ _1byte = dhcp_code_End;
+ tsk_buffer_append(output, &(_1byte), 1);
+
+bail:
+ return output;
+}
+
+tnet_dhcp_message_t* tnet_dhcp_message_deserialize(const struct tnet_dhcp_ctx_s *ctx, const uint8_t *data, tsk_size_t size)
+{
+ tnet_dhcp_message_t *message = 0;
+ uint8_t *dataPtr, *dataEnd, *dataStart;
+
+ if (!data || !size)
+ {
+ goto bail;
+ }
+
+ if (size < TNET_DHCP_MESSAGE_MIN_SIZE){
+ TSK_DEBUG_ERROR("DHCP message too short.");
+ goto bail;
+ }
+
+ if (!(message = tnet_dhcp_reply_create())){ /* If REQUEST OP will be overridedden */
+ TSK_DEBUG_ERROR("Failed to create new DHCP message.");
+ goto bail;
+ }
+
+ dataPtr = (uint8_t*)data;
+ dataStart = dataPtr;
+ dataEnd = (dataStart + size);
+
+ /*== op (1)*/
+ message->op = *(dataPtr++);
+ /*== htype (1) */
+ message->htype = *(dataPtr++);
+ /*== hlen (1) */
+ message->hlen = *(dataPtr++);
+ /*== htype (1) */
+ message->hops = *(dataPtr++);
+ /*== xid (4) */
+ message->xid = (uint32_t)tnet_htonl_2(dataPtr);
+ dataPtr += 4;
+ /*== secs (2) */
+ message->secs = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /*== flags (2) */
+ message->flags = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /*== ciaddr (4) */
+ message->ciaddr = (uint32_t)tnet_htonl_2(dataPtr);
+ dataPtr += 4;
+ /*== yiaddr (4) */
+ message->yiaddr = (uint32_t)tnet_htonl_2(dataPtr);
+ dataPtr += 4;
+ /*== siaddr (4) */
+ message->siaddr = (uint32_t)tnet_htonl_2(dataPtr);
+ dataPtr += 4;
+ /*== giaddr (4) */
+ message->giaddr = (uint32_t)tnet_htonl_2(dataPtr);
+ dataPtr += 4;
+ /*== chaddr (16[max]) */
+ memcpy(message->chaddr, dataPtr, message->hlen > 16 ? 16 : message->hlen);
+ dataPtr += 16;
+ /*== sname (64) */
+ memcpy(message->sname, dataPtr, 64);
+ dataPtr += 64;
+ /*== file (128) */
+ memcpy(message->file, dataPtr, 128);
+ dataPtr += 128;
+ /*== Magic Cookie (4) */
+ if (tnet_htonl_2(dataPtr) != TNET_DHCP_MAGIC_COOKIE){
+ TSK_DEBUG_ERROR("Invalid DHCP magic cookie.");
+ // Do not exit ==> continue parsing.
+ }
+ dataPtr += 4;
+
+ /*== options (variable) */
+ while (dataPtr < dataEnd && *dataPtr != dhcp_code_End)
+ {
+ tnet_dhcp_option_t* option = tnet_dhcp_option_deserialize(dataPtr, (tsk_size_t)(dataEnd - dataPtr));
+ if (option && option->value){
+
+ if (option->code == dhcp_code_DHCP_Msg_Type){
+ message->type = (tnet_dhcp_message_type_t)*TSK_BUFFER_TO_U8(option->value);
+ }
+
+ dataPtr += option->value->size + 2/*Code Len*/;
+ tsk_list_push_back_data(message->options, (void**)&option);
+ }
+ else break;
+ }
+
+bail:
+ return message;
+}
+
+
+const tnet_dhcp_option_t* tnet_dhcp_message_find_option(const tnet_dhcp_message_t *message, tnet_dhcp_option_code_t code)
+{
+ tsk_list_item_t *item;
+
+ if (!message){
+ goto bail;
+ }
+
+ tsk_list_foreach(item, message->options)
+ {
+ if (((tnet_dhcp_option_t*)item->data)->code == code){
+ return ((tnet_dhcp_option_t*)item->data);
+ }
+ }
+
+bail:
+ return 0;
+}
+
+int tnet_dhcp_message_add_codes(tnet_dhcp_message_t *self, tnet_dhcp_option_code_t codes[], unsigned codes_count)
+{
+ int ret = -1;
+
+ if (!self){
+ goto bail;
+ }
+ if (codes_count){
+ unsigned i;
+
+ tnet_dhcp_option_paramslist_t* option = (tnet_dhcp_option_paramslist_t*)tnet_dhcp_message_find_option(self, dhcp_code_Parameter_List);
+ if (!option){
+ tnet_dhcp_option_paramslist_t *option_paramslist = tnet_dhcp_option_paramslist_create();
+ option = option_paramslist;
+ tsk_list_push_back_data(self->options, (void**)&option_paramslist);
+ }
+
+ for (i = 0; i < codes_count; i++){
+ if ((ret = tnet_dhcp_option_paramslist_add_code(option, codes[i]))){
+ break;
+ }
+ }
+ }
+
+bail:
+ return ret;
+}
+
+
+//=================================================================================================
+// [[DHCP MESSAGE]] object definition
+//
+static tsk_object_t* tnet_dhcp_message_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_message_t *message = self;
+ if (message){
+ static uint32_t __dhcpmessage_unique_xid = 0;//(uint32_t)tsk_time_epoch();
+
+ message->op = va_arg(*app, tnet_dhcp_message_op_t);
+ message->htype = tnet_htype_Ethernet_10Mb;
+ message->hlen = 0x06;
+
+ message->xid = ++(__dhcpmessage_unique_xid);
+ message->options = tsk_list_create();
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_message_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_message_t *message = self;
+ if (message){
+ TSK_OBJECT_SAFE_FREE(message->options);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_message_def_s =
+{
+ sizeof(tnet_dhcp_message_t),
+ tnet_dhcp_message_ctor,
+ tnet_dhcp_message_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_message_def_t = &tnet_dhcp_message_def_s;
+
diff --git a/tinyNET/src/dhcp/tnet_dhcp_message.h b/tinyNET/src/dhcp/tnet_dhcp_message.h
new file mode 100644
index 0000000..c7005fa
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_message.h
@@ -0,0 +1,226 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp_message.h
+ * @brief DHCP Message as per RFC 2131 subclause 2.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef TNET_DHCP_MESSAGE_H
+#define TNET_DHCP_MESSAGE_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp_option.h"
+#include "tnet_hardwares.h"
+
+#include "tsk_buffer.h"
+
+TNET_BEGIN_DECLS
+
+struct tnet_dhcp_ctx_s;
+
+#define TNET_DHCP_MESSAGE_IS_REQUEST(self) ((self) && ((self)->op==dhcp_op_bootrequest))
+#define TNET_DHCP_MESSAGE_IS_REPLY(self) ((self) && ((self)->op==dhcp_op_bootreply))
+
+#define TNET_DHCP_MAGIC_COOKIE 0x63825363 /**< DHCP magic cookie (99, 130, 83 and 99 in decimal).*/
+
+#define TNET_DHCP_MESSAGE_MIN_SIZE 223 /* Is it rigth? */
+
+/** List of all supported DHCP message (see RFC 2131).
+*/
+typedef enum tnet_dhcp_message_type_e
+{
+ /**< DHCPDISCOVER - Client broadcast to locate available servers.
+ */
+ dhcp_type_discover = 1,
+
+ /**< DHCPOFFER - Server to client in response to DHCPDISCOVER with
+ offer of configuration parameters.
+ */
+ dhcp_type_offer = 2,
+
+ /**< DHCPREQUEST - Client message to servers either (a) requesting
+ offered parameters from one server and implicitly
+ declining offers from all others, (b) confirming
+ correctness of previously allocated address after,
+ e.g., system reboot, or (c) extending the lease on a
+ particular network address.
+ */
+ dhcp_type_request = 3,
+
+ /**< DHCPDECLINE - Client to server indicating network address is already
+ in use.
+ */
+ dhcp_type_decline = 4,
+
+ /**< DHCPACK - Server to client with configuration parameters,
+ including committed network address.
+ */
+ dhcp_type_ack = 5,
+
+ /**< DHCPNAK - Server to client indicating client's notion of network
+ address is incorrect (e.g., client has moved to new
+ subnet) or client's lease as expired
+ */
+ dhcp_type_nack = 6,
+
+ /**< DHCPRELEASE - Client to server relinquishing network address and
+ cancelling remaining lease.
+ */
+ dhcp_type_release = 7,
+
+ /**< DHCPINFORM - Client to server, asking only for local configuration
+ parameters; client already has externally configured
+ network address.
+ */
+ dhcp_type_inform = 8,
+}
+tnet_dhcp_message_type_t;
+
+/** DHCP message OP code / message type.
+*/
+typedef enum tnet_dhcp_message_op_e
+{
+ dhcp_op_bootrequest = 1,
+ dhcp_op_bootreply = 2
+}
+tnet_dhcp_message_op_t;
+
+/** BOOTP/DHCP message as per RFC 2131 subclause 2.
+*/
+typedef struct tnet_dhcp_message_s
+{
+ TSK_DECLARE_OBJECT;
+
+ /**< DHCP message type. Mandatory.
+ */
+ tnet_dhcp_message_type_t type;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | op (1) | htype (1) | hlen (1) | hops (1) |
+ +---------------+---------------+---------------+---------------+
+ | xid (4) |
+ +-------------------------------+-------------------------------+
+ | secs (2) | flags (2) |
+ +-------------------------------+-------------------------------+
+ | ciaddr (4) |
+ +---------------------------------------------------------------+
+ | yiaddr (4) |
+ +---------------------------------------------------------------+
+ | siaddr (4) |
+ +---------------------------------------------------------------+
+ | giaddr (4) |
+ +---------------------------------------------------------------+
+ | |
+ | chaddr (16) |
+ | |
+ | |
+ +---------------------------------------------------------------+
+ | |
+ | sname (64) |
+ +---------------------------------------------------------------+
+ | |
+ | file (128) |
+ +---------------------------------------------------------------+
+ | |
+ | options (variable) |
+ +---------------------------------------------------------------+
+ */
+
+ /**< Message op code / message type (1-byte).
+ 1 = BOOTREQUEST, 2 = BOOTREPLY
+ */
+ tnet_dhcp_message_op_t op;
+ /**< Hardware address type, see ARP section in "Assigned Numbers" RFC; e.g., '1' = 10mb ethernet.
+ For more information see RFC 1340.
+ */
+ tnet_hardware_type_t htype;
+ /**< Hardware address length (e.g. '6' for 10mb ethernet). tsk_strlen(chaddr).
+ */
+ uint8_t hlen;
+ /**< Client sets to zero, optionally used by relay agents when booting via a relay agent.
+ */
+ uint8_t hops;
+ /**< Transaction ID, a random number chosen by the client, used by the client
+ and server to associate messages and responses between a client and a server.
+ */
+ uint32_t xid;
+ /**< Filled in by client, seconds elapsed since client began address acquisition or renewal process.
+ */
+ uint16_t secs;
+ /**< Flags (see figure 2)
+ */
+ uint16_t flags;
+ /**< Client IP address; only filled in if client is in BOUND, RENEW or REBINDING
+ state and can respond to ARP requests.
+ */
+ uint32_t ciaddr;
+ /**< 'your' (client) IP address.
+ */
+ uint32_t yiaddr;
+ /**< IP address of next server to use in bootstrap;
+ returned in DHCPOFFER, DHCPACK by server.
+ */
+ uint32_t siaddr;
+ /**< Relay agent IP address, used in booting via a relay agent.
+ */
+ uint32_t giaddr;
+ /**< Client hardware address.
+ */
+ uint8_t chaddr[16];
+ /**< Optional server host name, null terminated string.
+ */
+ uint8_t sname[64];
+ /**<Boot file name, null terminated string; "generic" name or null in DHCPDISCOVER,
+ fully qualifieddirectory-path name in DHCPOFFER.
+ */
+ uint8_t file[128];
+ /**Optional parameters field. See the options documents for a list of defined options.
+ For more information please refer to RFC 2132, 1497 and 1533.
+ */
+ tnet_dhcp_options_L_t *options;
+}
+tnet_dhcp_message_t;
+
+typedef tsk_list_t tnet_dhcp_messages_L_t;
+typedef tnet_dhcp_message_t tnet_dhcp_request_t; /**< BOOTREQUEST message. */
+typedef tnet_dhcp_message_t tnet_dhcp_reply_t; /**< BOOTREPLY message. */
+
+tsk_buffer_t* tnet_dhcp_message_serialize(const struct tnet_dhcp_ctx_s *ctx, const tnet_dhcp_message_t *self);
+tnet_dhcp_message_t* tnet_dhcp_message_deserialize(const struct tnet_dhcp_ctx_s *ctx, const uint8_t *data, tsk_size_t size);
+const tnet_dhcp_option_t* tnet_dhcp_message_find_option(const tnet_dhcp_message_t *self, tnet_dhcp_option_code_t code);
+int tnet_dhcp_message_add_codes(tnet_dhcp_message_t *self, tnet_dhcp_option_code_t codes[], unsigned codes_count);
+
+TINYNET_API tnet_dhcp_message_t* tnet_dhcp_message_create(tnet_dhcp_message_op_t opcode);
+TINYNET_API tnet_dhcp_request_t* tnet_dhcp_request_create();
+TINYNET_API tnet_dhcp_message_t* tnet_dhcp_reply_create();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_message_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP_MESSAGE_H */
diff --git a/tinyNET/src/dhcp/tnet_dhcp_option.c b/tinyNET/src/dhcp/tnet_dhcp_option.c
new file mode 100644
index 0000000..3679a62
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_option.c
@@ -0,0 +1,326 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp_option.c
+ * @brief DHCP Options and BOOTP Vendor Extensions as per RFC 2132.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dhcp_option.h"
+
+#include "tnet_dhcp_option_sip.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+tnet_dhcp_option_t* tnet_dhcp_option_create(tnet_dhcp_option_code_t code)
+{
+ return tsk_object_new(tnet_dhcp_option_def_t, code);
+}
+
+tnet_dhcp_option_paramslist_t* tnet_dhcp_option_paramslist_create()
+{
+ return tsk_object_new(tnet_dhcp_option_paramslist_def_t);
+}
+
+tnet_dhcp_option_dns_t* tnet_dhcp_option_dns_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp_option_dns_def_t, payload, payload_size);
+}
+
+/** Initializes DHCPv4 option.
+ *
+ * @param [in,out] self The option to initialize.
+ * @param code The code of the option to initialize.
+ *
+ * @return Zero if succeed and non-zero error code otherwise.
+**/
+int tnet_dhcp_option_init(tnet_dhcp_option_t *self, tnet_dhcp_option_code_t code)
+{
+ if(self)
+ {
+ if(!self->initialized)
+ {
+ self->code = code;
+ //option->value = tsk_buffer_create_null();
+
+ self->initialized = tsk_true;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+int tnet_dhcp_option_deinit(tnet_dhcp_option_t *self)
+{
+ if(self)
+ {
+ if(self->initialized)
+ {
+ TSK_OBJECT_SAFE_FREE(self->value);
+
+ self->initialized = tsk_false;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+tnet_dhcp_option_t* tnet_dhcp_option_deserialize(const void* data, tsk_size_t size)
+{
+ tnet_dhcp_option_t *option = 0;
+ uint8_t* dataPtr = ((uint8_t*)data);
+ //uint8_t* dataEnd = (dataPtr+size);
+
+ tnet_dhcp_option_code_t code;
+ uint8_t len;
+
+ /* Check validity */
+ if(!dataPtr || size<2/*Code Len*/){
+ goto bail;
+ }
+
+ code = (tnet_dhcp_option_code_t)*dataPtr++;
+ len = *dataPtr++;
+
+ switch(code)
+ {
+ case dhcp_code_SIP_Servers_DHCP_Option:
+ {
+ option = (tnet_dhcp_option_t *)tnet_dhcp_option_sip_create(dataPtr, len);
+ break;
+ }
+
+ case dhcp_code_Domain_Server:
+ {
+ option = (tnet_dhcp_option_t *)tnet_dhcp_option_dns_create(dataPtr, len);
+ break;
+ }
+
+ default:
+ {
+ option = tnet_dhcp_option_create(code);
+ }
+ }
+
+ /* In all case */
+ if(option && !option->value && len){
+ option->value = tsk_buffer_create((((uint8_t*)data) + 2/*Code Len*/), len);
+ }
+
+bail:
+ return option;
+}
+
+int tnet_dhcp_option_serialize(const tnet_dhcp_option_t* self, tsk_buffer_t *output)
+{
+ if(!self || !output){
+ return -1;
+ }
+
+ /* Code */
+ tsk_buffer_append(output, &(self->code), 1);
+
+ if(self->value){
+ /* Length */
+ tsk_buffer_append(output, &(self->value->size), 1);
+
+ /* Value */
+ tsk_buffer_append(output, self->value->data, self->value->size);
+ }
+ else{
+ /* Length */
+ static uint8_t zero = 0x00;
+ tsk_buffer_append(output, &zero, 1);
+ }
+
+ return 0;
+}
+
+int tnet_dhcp_option_serializeex(tnet_dhcp_option_code_t code, uint8_t length, const void* value, tsk_buffer_t *output)
+{
+ if(value && length && output){
+ tsk_buffer_append(output, &(code), 1);
+ tsk_buffer_append(output, &(length), 1);
+ tsk_buffer_append(output, value, length);
+
+ return 0;
+ }
+ return -1;
+}
+
+//
+// [[DHCP OPTION]] object definition
+//
+static tsk_object_t* tnet_dhcp_option_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_option_t *option = self;
+ if(option){
+ tnet_dhcp_option_init(option, va_arg(*app, tnet_dhcp_option_code_t));
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_option_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_option_t *option = self;
+ if(option){
+ tnet_dhcp_option_deinit(option);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_option_def_s =
+{
+ sizeof(tnet_dhcp_option_t),
+ tnet_dhcp_option_ctor,
+ tnet_dhcp_option_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_option_def_t = &tnet_dhcp_option_def_s;
+
+
+
+/*=======================================================================================
+* RFC 2132 - 9.8. Parameter Request List
+*=======================================================================================*/
+int tnet_dhcp_option_paramslist_add_code(tnet_dhcp_option_paramslist_t* self, tnet_dhcp_option_code_t code)
+{
+ if(self){
+ if(!TNET_DHCP_OPTION(self)->value){
+ TNET_DHCP_OPTION(self)->value = tsk_buffer_create_null();
+ }
+ return tsk_buffer_append(TNET_DHCP_OPTION(self)->value, &code, 1);
+ }
+ return -1;
+}
+
+//
+// [[DHCP OPTION - RFC 2132 9.8. Parameter Request List]] object definition
+//
+static tsk_object_t* tnet_dhcp_option_paramslist_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_option_paramslist_t *option = self;
+ if(option){
+ /* init base */
+ tnet_dhcp_option_init(TNET_DHCP_OPTION(option), dhcp_code_Parameter_List);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_option_paramslist_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_option_paramslist_t *option = self;
+ if(option){
+ /* deinit base */
+ tnet_dhcp_option_deinit(TNET_DHCP_OPTION(option));
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_option_paramslist_def_s =
+{
+ sizeof(tnet_dhcp_option_paramslist_t),
+ tnet_dhcp_option_paramslist_ctor,
+ tnet_dhcp_option_paramslist_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_option_paramslist_def_t = &tnet_dhcp_option_paramslist_def_s;
+
+
+/*=======================================================================================
+* RFC 2132 - 3.8. Domain Name Server Option
+*=======================================================================================*/
+//
+// [[DHCP OPTION - RFC 2132 3.8. Domain Name Server Option]] object definition
+//
+static tsk_object_t* tnet_dhcp_option_dns_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_option_dns_t *option = self;
+ if(option){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ const uint8_t* payloadPtr = (const uint8_t*)payload;
+ const uint8_t* payloadEnd = (payloadPtr + payload_size);
+
+ /* init base */
+ tnet_dhcp_option_init(TNET_DHCP_OPTION(option), dhcp_code_Domain_Server);
+
+ option->servers = tsk_list_create();
+
+ if(payload_size<4 || payload_size%4){
+ TSK_DEBUG_ERROR("DHCP - The minimum length for this option is 4 octets, and the length MUST always be a multiple of 4.");
+ }
+ else{
+ tsk_size_t i;
+ char* ip4 = 0;
+ uint32_t address;
+ tsk_string_t* addrstring;
+
+ for(i=0; i<payload_size && (payloadPtr< payloadEnd); i+=4){
+ /*
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 6 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ */
+ address = (uint32_t)tnet_htonl_2(payloadPtr);
+ tsk_sprintf(&ip4, "%u.%u.%u.%u", (address>>24)&0xFF, (address>>16)&0xFF, (address>>8)&0xFF, (address>>0)&0xFF);
+
+ addrstring = tsk_string_create(ip4);
+ tsk_list_push_back_data(option->servers, (void*)&addrstring);
+
+ TSK_FREE(ip4);
+ payloadPtr+= 4;
+ }
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_option_dns_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_option_dns_t *option = self;
+ if(option){
+ /* deinit base */
+ tnet_dhcp_option_deinit(TNET_DHCP_OPTION(option));
+
+ TSK_OBJECT_SAFE_FREE(option->servers);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_option_dns_def_s =
+{
+ sizeof(tnet_dhcp_option_dns_t),
+ tnet_dhcp_option_dns_ctor,
+ tnet_dhcp_option_dns_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_option_dns_def_t = &tnet_dhcp_option_dns_def_s;
diff --git a/tinyNET/src/dhcp/tnet_dhcp_option.h b/tinyNET/src/dhcp/tnet_dhcp_option.h
new file mode 100644
index 0000000..0d16ac1
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_option.h
@@ -0,0 +1,291 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp_option.h
+ * @brief DHCP Options and BOOTP Vendor Extensions as per RFC 2132.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef TNET_DHCP_OPTION_H
+#define TNET_DHCP_OPTION_H
+
+#include "tinynet_config.h"
+
+#include "tsk_buffer.h"
+#include "tsk_string.h"
+
+TNET_BEGIN_DECLS
+
+#define TNET_DHCP_OPTION(self) ((tnet_dhcp_option_t*)(self))
+
+typedef enum tnet_dhcp_option_code_e
+{
+ dhcp_code_Pad= 0 ,/**< Pad 0 None [RFC2132] */
+ dhcp_code_Subnet_Mask= 1 ,/**< Subnet Mask 4 Subnet Mask Value [RFC2132] */
+ dhcp_code_Time_Offset= 2 ,/**< Time Offset 4 Time Offset in Seconds from UTC [RFC2132] (note: deprecated by 100 and 101) */
+ dhcp_code_Router= 3 ,/**< Router N N/4 Router addresses [RFC2132] */
+ dhcp_code_Time_Server= 4 ,/**< Time Server N N/4 Timeserver addresses [RFC2132] */
+ dhcp_code_Name_Server= 5 ,/**< Name Server N N/4 IEN-116 Server addresses [RFC2132] */
+ dhcp_code_Domain_Server= 6 ,/**< Domain Server N N/4 DNS Server addresses [RFC2132] */
+ dhcp_code_Log_Server= 7 ,/**< Log Server N N/4 Logging Server addresses [RFC2132] */
+ dhcp_code_Quotes_Server= 8 ,/**< Quotes Server N N/4 Quotes Server addresses [RFC2132] */
+ dhcp_code_LPR_Server= 9 ,/**< LPR Server N N/4 Printer Server addresses [RFC2132] */
+ dhcp_code_Impress_Server= 10 ,/**< Impress Server N N/4 Impress Server addresses [RFC2132] */
+ dhcp_code_RLP_Server= 11 ,/**< RLP Server N N/4 RLP Server addresses [RFC2132] */
+ dhcp_code_Hostname= 12 ,/**< Hostname N Hostname string [RFC2132] */
+ dhcp_code_Boot_File_Size= 13 ,/**< Boot File Size 2 Size of boot file in 512 byte chunks [RFC2132] */
+ dhcp_code_Merit_Dump_File= 14 ,/**< Merit Dump File N Client to dump and name the file to dump it to [RFC2132] */
+ dhcp_code_Domain_Name= 15 ,/**< Domain Name N The DNS domain name of the client [RFC2132] */
+ dhcp_code_Swap_Server= 16 ,/**< Swap Server N Swap Server address [RFC2132] */
+ dhcp_code_Root_Path= 17 ,/**< Root Path N Path name for root disk [RFC2132] */
+ dhcp_code_Extension_File= 18 ,/**< Extension File N Path name for more BOOTP info [RFC2132] */
+ dhcp_code_Forward_On_Off= 19 ,/**< Forward On/Off 1 Enable/Disable IP Forwarding [RFC2132] */
+ dhcp_code_SrcRte_On_Off = 20 ,/**< SrcRte On/Off 1 Enable/Disable Source Routing [RFC2132] */
+ dhcp_code_Policy_Filter= 21 ,/**< Policy Filter N Routing Policy Filters [RFC2132] */
+ dhcp_code_Max_DG_Assembly= 22 ,/**< Max DG Assembly 2 Max Datagram Reassembly Size [RFC2132] */
+ dhcp_code_Default_IP_TTL= 23 ,/**< Default IP TTL 1 Default IP Time to Live [RFC2132] */
+ dhcp_code_MTU_Timeout= 24 ,/**< MTU Timeout 4 Path MTU Aging Timeout [RFC2132] */
+ dhcp_code_MTU_Plateau= 25 ,/**< MTU Plateau N Path MTU Plateau Table [RFC2132] */
+ dhcp_code_MTU_Interface= 26 ,/**< MTU Interface 2 Interface MTU Size [RFC2132] */
+ dhcp_code_MTU_Subnet= 27 ,/**< MTU Subnet 1 All Subnets are Local [RFC2132] */
+ dhcp_code_Broadcast_Address= 28 ,/**< Broadcast Address 4 Broadcast Address [RFC2132] */
+ dhcp_code_Mask_Discovery= 29 ,/**< Mask Discovery 1 Perform Mask Discovery [RFC2132] */
+ dhcp_code_Mask_Supplier= 30 ,/**< Mask Supplier 1 Provide Mask to Others [RFC2132] */
+ dhcp_code_Router_Discovery= 31 ,/**< Router Discovery 1 Perform Router Discovery [RFC2132] */
+ dhcp_code_Router_Request= 32 ,/**< Router Request 4 Router Solicitation Address [RFC2132] */
+ dhcp_code_Static_Route= 33 ,/**< Static Route N Static Routing Table [RFC2132] */
+ dhcp_code_Trailers= 34 ,/**< Trailers 1 Trailer Encapsulation [RFC2132] */
+ dhcp_code_ARP_Timeout= 35 ,/**< ARP Timeout 4 ARP Cache Timeout [RFC2132] */
+ dhcp_code_Ethernet= 36 ,/**< Ethernet 1 Ethernet Encapsulation [RFC2132] */
+ dhcp_code_Default_TCP_TTL= 37 ,/**< Default TCP TTL 1 Default TCP Time to Live [RFC2132] */
+ dhcp_code_Keepalive_Time= 38 ,/**< Keepalive Time 4 TCP Keepalive Interval [RFC2132] */
+ dhcp_code_Keepalive_Data= 39 ,/**< Keepalive Data 1 TCP Keepalive Garbage [RFC2132] */
+ dhcp_code_NIS_Domain= 40 ,/**< NIS Domain N NIS Domain Name [RFC2132] */
+ dhcp_code_NIS_Servers= 41 ,/**< NIS Servers N NIS Server Addresses [RFC2132] */
+ dhcp_code_NTP_Servers= 42 ,/**< NTP Servers N NTP Server Addresses [RFC2132] */
+ dhcp_code_Vendor_Specific= 43 ,/**< Vendor Specific N Vendor Specific Information [RFC2132] */
+ dhcp_code_NETBIOS_Name_Srv= 44 ,/**< NETBIOS Name Srv N NETBIOS Name Servers [RFC2132] */
+ dhcp_code_NETBIOS_Dist_Srv= 45 ,/**< NETBIOS Dist Srv N NETBIOS Datagram Distribution [RFC2132] */
+ dhcp_code_NETBIOS_Node_Type= 46 ,/**< NETBIOS Node Type 1 NETBIOS Node Type [RFC2132] */
+ dhcp_code_NETBIOS_Scope= 47 ,/**< NETBIOS Scope N NETBIOS Scope [RFC2132] */
+ dhcp_code_X_Window_Font= 48 ,/**< X Window Font N X Window Font Server [RFC2132] */
+ dhcp_code_X_Window_Manager= 49 ,/**< X Window Manager N X Window Display Manager [RFC2132] */
+ dhcp_code_Address_Request= 50 ,/**< Address Request 4 Requested IP Address [RFC2132] */
+ dhcp_code_Address_Time= 51 ,/**< Address Time 4 IP Address Lease Time [RFC2132] */
+ dhcp_code_Overload= 52 ,/**< Overload 1 Overload "sname" or "file" [RFC2132] */
+ dhcp_code_DHCP_Msg_Type= 53 ,/**< DHCP Msg Type 1 DHCP Message Type [RFC2132] */
+ dhcp_code_DHCP_Server_Id= 54 ,/**< DHCP Server Id 4 DHCP Server Identification [RFC2132] */
+ dhcp_code_Parameter_List= 55 ,/**< Parameter List N Parameter Request List [RFC2132] */
+ dhcp_code_DHCP_Error_Message= 56 ,/**< DHCP Message N DHCP Error Message [RFC2132] */
+ dhcp_code_DHCP_Max_Msg_Size= 57 ,/**< DHCP Max Msg Size 2 DHCP Maximum Message Size [RFC2132] */
+ dhcp_code_Renewal_Time= 58 ,/**< Renewal Time 4 DHCP Renewal (T1) Time [RFC2132] */
+ dhcp_code_Rebinding_Time= 59 ,/**< Rebinding Time 4 DHCP Rebinding (T2) Time [RFC2132] */
+ dhcp_code_Class_Id= 60 ,/**< Class Id N Class Identifier [RFC2132] */
+ dhcp_code_Client_Id= 61 ,/**< Client Id N Client Identifier [RFC2132] */
+ dhcp_code_NetWare_IP_Domain= 62 ,/**< NetWare/IP Domain N NetWare/IP Domain Name [RFC2242] */
+ dhcp_code_NetWare_IP_Option= 63 ,/**< NetWare/IP Option N NetWare/IP sub Options [RFC2242] */
+ dhcp_code_NIS_Domain_Name= 64 ,/**< NIS-Domain-Name N NIS+ v3 Client Domain Name [RFC2132] */
+ dhcp_code_NIS_Server_Addr = 65 ,/**< NIS-Server-Addr N NIS+ v3 Server Addresses [RFC2132] */
+ dhcp_code_Server_Name= 66 ,/**< Server-Name N TFTP Server Name [RFC2132] */
+ dhcp_code_Bootfile_Name= 67 ,/**< Bootfile-Name N Boot File Name [RFC2132] */
+ dhcp_code_Home_Agent_Addrs= 68 ,/**< Home-Agent-Addrs N Home Agent Addresses [RFC2132] */
+ dhcp_code_SMTP_Server= 69 ,/**< SMTP-Server N Simple Mail Server Addresses [RFC2132] */
+ dhcp_code_POP3_Server= 70 ,/**< POP3-Server N Post Office Server Addresses [RFC2132] */
+ dhcp_code_NNTP_Server= 71 ,/**< NNTP-Server N Network News Server Addresses [RFC2132] */
+ dhcp_code_WWW_Server= 72 ,/**< WWW-Server N WWW Server Addresses [RFC2132] */
+ dhcp_code_Finger_Server= 73 ,/**< Finger-Server N Finger Server Addresses [RFC2132] */
+ dhcp_code_IRC_Server= 74 ,/**< IRC-Server N Chat Server Addresses [RFC2132] */
+ dhcp_code_StreetTalk_Server= 75 ,/**< StreetTalk-Server N StreetTalk Server Addresses [RFC2132] */
+ dhcp_code_STDA_Server= 76 ,/**< STDA-Server N ST Directory Assist. Addresses [RFC2132] */
+ dhcp_code_User_Class= 77 ,/**< User-Class N User Class Information [RFC3004] */
+ dhcp_code_Directory_Agent = 78 ,/**< Directory Agent N directory agent information [RFC2610] */
+ dhcp_code_Service_Scope = 79 ,/**< Service Scope N service location agent scope [RFC2610] */
+ dhcp_code_Rapid_Commit= 80 ,/**< Rapid Commit 0 Rapid Commit [RFC4039] */
+ dhcp_code_Client_FQDN = 81 ,/**< Client FQDN N Fully Qualified Domain Name [RFC4702] */
+ dhcp_code_Relay_Agent_Information= 82 ,/**< Relay Agent Information N Relay Agent Information [RFC3046] */
+ dhcp_code_iSNS= 83 ,/**< iSNS N Internet Storage Name Service [RFC4174] */
+ //84 REMOVED/Unassigned [RFC3679] */
+ dhcp_code_NDS_Servers= 85 ,/**< NDS Servers N Novell Directory Services [RFC2241] */
+ dhcp_code_NDS_Tree_Name= 86 ,/**< NDS Tree Name N Novell Directory Services [RFC2241] */
+ dhcp_code_NDS_Context= 87 ,/**< NDS Context N Novell Directory Services [RFC2241] */
+ dhcp_code_BCMCS_Controller_Domain_Name_list= 88 ,/**< BCMCS Controller Domain Name list [RFC4280] */
+ dhcp_code_BCMCS_Controller_IPv4_address_option= 89 ,/**< BCMCS Controller IPv4 address option [RFC4280] */
+ dhcp_code_Authentication= 90 ,/**< Authentication N Authentication [RFC3118] */
+ dhcp_code_client_last_transaction_time= 91 ,/**< client-last-transaction-time option [RFC4388] */
+ dhcp_code_associated_ip= 92 ,/**< associated-ip option [RFC4388] */
+ dhcp_code_Client_System = 93 ,/**< Client System N Client System Architecture [RFC4578] */
+ dhcp_code_Client_NDI = 94 ,/**< Client NDI N Client Network Device Interface [RFC4578] */
+ dhcp_code_LDAP= 95 ,/**< LDAP N Lightweight Directory Access Protocol [RFC3679] */
+ dhcp_code_REMOVED_Unassigned= 96 ,/**< REMOVED/Unassigned [RFC3679] */
+ dhcp_code_UUID_GUID= 97 ,/**< UUID/GUID N UUID/GUID-based Client Identifier [RFC4578] */
+ dhcp_code_User_Auth= 98 ,/**< User-Auth N Open Group's User Authentication [RFC2485] */
+ dhcp_code_GEOCONF_CIVIC= 99 ,/**< GEOCONF_CIVIC [RFC4776] */
+ dhcp_code_PCode= 100 ,/**< PCode N IEEE 1003.1 TZ String [RFC4833] */
+ dhcp_code_TCode= 101 ,/**< TCode N Reference to the TZ Database [RFC4833] */
+ //102-107 REMOVED/Unassigned [RFC3679]
+ //108 REMOVED/Unassigned [RFC3679]
+ //109 Unassigned [RFC3679]
+ //110 REMOVED/Unassigned [RFC3679]
+ //111 Unassigned [RFC3679]
+ dhcp_code_Netinfo_Address= 112 ,/**< Netinfo Address N NetInfo Parent Server Address [RFC3679] */
+ dhcp_code_Netinfo_Tag= 113 ,/**< Netinfo Tag N NetInfo Parent Server Tag [RFC3679] */
+ dhcp_code_= 114 ,/**< URL N URL [RFC3679] */
+ //115 REMOVED/Unassigned [RFC3679]
+ dhcp_code_Auto_Config= 116 ,/**< Auto-Config N DHCP Auto-Configuration [RFC2563] */
+ dhcp_code_Name_Service_Search= 117 ,/**< Name Service Search N Name Service Search [RFC2937] */
+ dhcp_code_Subnet_Selection_Option= 118 ,/**< Subnet Selection Option 4 Subnet Selection Option [RFC3011] */
+ dhcp_code_Domain_Search= 119 ,/**< Domain Search N DNS domain search list [RFC3397] */
+ dhcp_code_SIP_Servers_DHCP_Option= 120 ,/**< SIP Servers DHCP Option N SIP Servers DHCP Option [RFC3361] */
+ dhcp_code_Classless_Static_Route_Option= 121 ,/**< Classless Static Route Option N Classless Static Route Option [RFC3442] */
+ dhcp_code_CCC= 122 ,/**< CCC N CableLabs Client Configuration [RFC3495] */
+ dhcp_code_GeoConf_Option= 123 ,/**< GeoConf Option 16 GeoConf Option [RFC3825] */
+ dhcp_code_V_I_Vendor_Class= 124 ,/**< V-I Vendor Class Vendor-Identifying Vendor Class [RFC3925] */
+ dhcp_code_V_I_Vendor_Specific_Information= 125 ,/**< V-I Vendor-Specific Information Vendor-Identifying Vendor-Specific Information [RFC3925] */
+ //dhcp_code_= 126 ,/**< Removed/Unassigned [RFC3679] */
+ //dhcp_code_= 127 ,/**< Removed/Unassigned [RFC3679] */
+ //dhcp_code_PXE - undefined= 128 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_Etherboot_signature= 128 ,/**< Etherboot signature. 6 bytes: E4:45:74:68:00:00 */
+ dhcp_code_DOCSIS= 128 ,/**< DOCSIS "full security" server IP address */
+ dhcp_code_TFTP_Server_IP= 128 ,/**< TFTP Server IP address (for IP Phone software load) */
+ //dhcp_code_= 129 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_Kernel_options= 129 ,/**< Kernel options. Variable length string */
+ dhcp_code_Call_Server_IP= 129 ,/**< Call Server IP address */
+ //dhcp_code_= 130 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_Ethernet_interface= 130 ,/**< Ethernet interface. Variable length string. */
+ dhcp_code_Discrimination= 130 ,/**< Discrimination string (to identify vendor) */
+ //dhcp_code_= 131 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_Remote_statistics_server_IP= 131 ,/**< Remote statistics server IP address */
+ //dhcp_code_= 132 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_IEEE_802_1Q_VLAN_ID= 132 ,/**< IEEE 802.1Q VLAN ID */
+ //dhcp_code_= 133 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_IEEE_802_1D_p= 133 ,/**< IEEE 802.1D/p Layer 2 Priority */
+ //dhcp_code_= 134 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_DSCP= 134 ,/**< Diffserv Code Point (DSCP) for VoIP signalling and media streams */
+ //dhcp_code_= 135 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_HTTP_Proxy= 135 ,/**< HTTP Proxy for phone-specific applications */
+ dhcp_code_OPTION_PANA_AGENT= 136 ,/**< OPTION_PANA_AGENT [RFC5192] */
+ dhcp_code_OPTION_V4_LOST= 137 ,/**< OPTION_V4_LOST [RFC5223] */
+ dhcp_code_OPTION_CAPWAP_AC_V4= 138 ,/**< OPTION_CAPWAP_AC_V4 N CAPWAP Access Controller addresses [RFC5417] */
+ dhcp_code_OPTION_IPv4_Address_MoS= 139 ,/**< OPTION-IPv4_Address-MoS N a series of suboptions [RFC5678] */
+ dhcp_code_OPTION_IPv4_FQDN_MoS= 140 ,/**< OPTION-IPv4_FQDN-MoS N a series of suboptions [RFC5678] */
+ //141-149 Unassigned [RFC3942] */
+ dhcp_code_TFTP_server_address= 150 ,/**< TFTP server address (Tentatively Assigned - 2005-06-23) */
+ dhcp_code_Etherboot= 150 ,/**< Etherboot */
+ dhcp_code_GRUB_configuration_path_name= 150 ,/**< GRUB configuration path name */
+ //151-174 Unassigned [RFC3942]
+ //dhcp_code_Etherboot= 175 ,/**< Etherboot (Tentatively Assigned - 2005-06-23) */
+ dhcp_code_IP_Telephone= 176 ,/**< IP Telephone (Tentatively Assigned - 2005-06-23) */
+ //dhcp_code_Etherboot= 177 ,/**< Etherboot (Tentatively Assigned - 2005-06-23) */
+ dhcp_code_PacketCable_and_CableHome= 177 ,/**< PacketCable and CableHome (replaced by 122) */
+ //178-207 Unassigned [RFC3942]
+ dhcp_code_PXELINUX_Magic= 208 ,/**< PXELINUX Magic 4 magic string = F1:00:74:7E [RFC5071] Deprecated */
+ dhcp_code_Configuration_File= 209 ,/**< Configuration File N Configuration file [RFC5071] */
+ dhcp_code_Path_Prefix= 210 ,/**< Path Prefix N Path Prefix Option [RFC5071] */
+ dhcp_code_Reboot_Time = 211 ,/**< Reboot Time 4 Reboot Time [RFC5071] */
+ // 212-219 Unassigned
+ dhcp_code_Subnet_Allocation= 220 ,/**< Subnet Allocation Option (Tentatively Assigned - 2005-06-23) */
+ dhcp_code_Virtual_Subnet= 221 ,/**< Virtual Subnet Selection Option (Tentatively Assigned - 2005-06-23) */
+ // 222-223 Unassigned [RFC3942]
+ //224-254 Reserved (Private Use)
+ dhcp_code_null=224 ,
+ dhcp_code_End= 255 ,/**< End 0 None [RFC2132] */
+}
+tnet_dhcp_option_code_t;
+
+/** DHCP/BOOTP option as per RFC 2132.
+* Format ==> subclause 2.
+*/
+typedef struct tnet_dhcp_option_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_bool_t initialized;
+
+ tnet_dhcp_option_code_t code; /**< 1-byte option-code. */
+ tsk_buffer_t *value;
+}
+tnet_dhcp_option_t;
+
+typedef tsk_list_t tnet_dhcp_options_L_t;
+
+#define TNET_DECLARE_DHCP_OPTION tnet_dhcp_option_t dhcp_option
+
+int tnet_dhcp_option_init(tnet_dhcp_option_t *self, tnet_dhcp_option_code_t code);
+int tnet_dhcp_option_deinit(tnet_dhcp_option_t *self);
+
+tnet_dhcp_option_t* tnet_dhcp_option_deserialize(const void* data, tsk_size_t size);
+int tnet_dhcp_option_serialize(const tnet_dhcp_option_t* self, tsk_buffer_t *output);
+int tnet_dhcp_option_serializeex(tnet_dhcp_option_code_t code, uint8_t length, const void* value, tsk_buffer_t *output);
+
+/*=======================================================================================
+* RFC 2132 - 9.8. Parameter Request List
+*=======================================================================================*/
+
+/** Parameter Request List Option */
+typedef struct tnet_dhcp_option_paramslist_s
+{
+ TNET_DECLARE_DHCP_OPTION;
+
+ /* RFC 2132 - 9.8. Parameter Request List
+ Code Len Option Codes
+ +-----+-----+-----+-----+---
+ | 55 | n | c1 | c2 | ...
+ +-----+-----+-----+-----+---
+ */
+}
+tnet_dhcp_option_paramslist_t;
+int tnet_dhcp_option_paramslist_add_code(tnet_dhcp_option_paramslist_t* self, tnet_dhcp_option_code_t code);
+
+/*=======================================================================================
+* RFC 2132 - 3.8. Domain Name Server Option
+*=======================================================================================*/
+
+/** Domain Name Server Option */
+typedef struct tnet_dhcp_option_dns_s
+{
+ TNET_DECLARE_DHCP_OPTION;
+
+ /* RFC 2132 - 3.8. Domain Name Server Option
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 6 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ */
+ tsk_strings_L_t *servers;
+}
+tnet_dhcp_option_dns_t;
+
+TINYNET_API tnet_dhcp_option_t* tnet_dhcp_option_create(tnet_dhcp_option_code_t code);
+TINYNET_API tnet_dhcp_option_paramslist_t* tnet_dhcp_option_paramslist_create();
+TINYNET_API tnet_dhcp_option_dns_t* tnet_dhcp_option_dns_create(const void* payload, tsk_size_t payload_size);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_option_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ns_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_option_paramslist_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_option_dns_def_t;
+
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP_OPTION_H */
diff --git a/tinyNET/src/dhcp/tnet_dhcp_option_sip.c b/tinyNET/src/dhcp/tnet_dhcp_option_sip.c
new file mode 100644
index 0000000..dd28953
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_option_sip.c
@@ -0,0 +1,131 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp_option_sip.c
+ * @brief Dynamic Host Configuration Protocol (DHCP-for-IPv4) Option for
+ * Session Initiation Protocol (SIP) Servers as per RFC 3361.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dhcp_option_sip.h"
+
+#include "dns/tnet_dns_rr.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+
+tnet_dhcp_option_sip_t* tnet_dhcp_option_sip_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp_option_sip_def_t, payload, payload_size);
+}
+
+//
+// [[DHCP SIP4]] object definition
+//
+static tsk_object_t* tnet_dhcp_option_sip_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_option_sip_t *option = self;
+ if(option){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ const uint8_t* payloadPtr = (const uint8_t*)payload;
+ const uint8_t* payloadEnd = (payloadPtr + payload_size);
+
+ /* init base */
+ tnet_dhcp_option_init(TNET_DHCP_OPTION(option), dhcp_code_SIP_Servers_DHCP_Option);
+
+ option->servers = tsk_list_create();
+
+ /* Set values as per RFC 3361. */
+ if(*payloadPtr == 0){ /* enc=0 */
+ /*
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ |120|27 | 0 | 7 |'e'|'x'|'a'|'m'|'p'|'l'|'e'| 3 |'c'|'o'|'m'| 0 |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+ | 7
+ |'e'|'x'|'a'|'m'|'p'|'l'|'e'| 3 |'n'|'e'|'t'| 0 | +---+---+---
+ +---+---+---+---+---+---+---+---+---+---+
+ */
+ tsk_size_t offset = 1;
+ char* server = 0;
+ payloadPtr++;
+ while((payloadPtr < payloadEnd) && !tnet_dns_rr_qname_deserialize(payload, &server, &offset)){
+ tsk_string_t* string = tsk_string_create(server);
+ tsk_list_push_back_data(option->servers, (void*)&string);
+ TSK_FREE(server);
+ payloadPtr += offset;
+ }
+ }
+ else{
+ /*
+ Code Len enc Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 120 | n | 1 | a1 | a2 | a3 | a4 | a1 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ */
+ uint32_t address;
+ tsk_string_t* addrstring;
+ char* ip4 = 0;
+
+ while(payloadPtr < payloadEnd){
+ ++payloadPtr;
+ address = tnet_htonl_2(payloadPtr);
+
+ tsk_sprintf(&ip4, "%u.%u.%u.%u", (address>>24)&0xFF, (address>>16)&0xFF, (address>>8)&0xFF, (address>>0)&0xFF);
+
+ addrstring = tsk_string_create(ip4);
+ tsk_list_push_back_data(option->servers, (void*)&addrstring);
+
+ TSK_FREE(ip4);
+
+ payloadPtr+= 4;
+ }
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_option_sip_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_option_sip_t *option = self;
+ if(option){
+ /* deinit base */
+ tnet_dhcp_option_deinit(TNET_DHCP_OPTION(option));
+
+ TSK_OBJECT_SAFE_FREE(option->servers);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_option_sip_def_s =
+{
+ sizeof(tnet_dhcp_option_sip_t),
+ tnet_dhcp_option_sip_ctor,
+ tnet_dhcp_option_sip_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_option_sip_def_t = &tnet_dhcp_option_sip_def_s;
diff --git a/tinyNET/src/dhcp/tnet_dhcp_option_sip.h b/tinyNET/src/dhcp/tnet_dhcp_option_sip.h
new file mode 100644
index 0000000..2e35bf5
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_option_sip.h
@@ -0,0 +1,62 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp_option_sip.h
+ * @brief Dynamic Host Configuration Protocol (DHCP-for-IPv4) Option for
+ * Session Initiation Protocol (SIP) Servers as per RFC 3361.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef tnet_dhcp_option_sip_H
+#define tnet_dhcp_option_sip_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp_option.h"
+
+#include "tsk_string.h"
+
+TNET_BEGIN_DECLS
+
+typedef struct tnet_dhcp_option_sip_s
+{
+ TNET_DECLARE_DHCP_OPTION;
+
+ /* RFC 3361 subclause 3.1
+ Code Len enc DNS name of SIP server
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 120 | n | 0 | s1 | s2 | s3 | s4 | s5 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ */
+ tsk_strings_L_t *servers;
+}
+tnet_dhcp_option_sip_t;
+
+TINYNET_API tnet_dhcp_option_sip_t* tnet_dhcp_option_sip_create(const void* payload, tsk_size_t payload_size);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_option_sip_def_t;
+
+TNET_END_DECLS
+
+#endif /* #define tnet_dhcp_option_sip_H */
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6.c b/tinyNET/src/dhcp6/tnet_dhcp6.c
new file mode 100644
index 0000000..8e2fdb7
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6.c
@@ -0,0 +1,269 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp6.c
+ * @brief Dynamic Host Configuration Protocol for IPv6 (DHCPv6) as per RFC 3315.
+ * Also implement: RFC 3319, 3633, 3646, 3736, 4242, 5007 ...
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dhcp6.h"
+
+#include "tsk_string.h"
+#include "tsk_debug.h"
+#include "tsk_memory.h"
+#include "tsk_time.h"
+#include "tsk_thread.h"
+
+
+/**@defgroup tnet_dhcp6_group DHCPv6 (RFC 3315) implementation.
+* Dynamic Host Configuration Protocol for IPv6 (DHCPv6) as per RFC 3315.
+* Also implement: RFC 3319, 3633, 3646, 3736, 4242, 5007 ...
+*/
+
+tnet_dhcp6_ctx_t* tnet_dhcp6_ctx_create()
+{
+ return tsk_object_new(tnet_dhcp6_ctx_def_t);
+}
+
+/**@ingroup tnet_dhcp6_group
+*/
+tnet_dhcp6_reply_t* tnet_dhcp6_send_request(const tnet_dhcp6_ctx_t* ctx, tnet_dhcp6_request_t* request)
+{
+ tsk_buffer_t *output;
+ tnet_dhcp6_reply_t* reply = 0;
+ int ret;
+ struct timeval tv;
+ fd_set set;
+ uint64_t timeout = 0;
+ tsk_list_item_t *item;
+ const tnet_interface_t *iface;
+ tnet_ip_t bestsource;
+
+ tnet_socket_t *localsocket6 = 0;
+ struct sockaddr_storage server;
+
+ if(!ctx || !request){
+ goto bail;
+ }
+
+ if((ret = tnet_getbestsource(TNET_DHCP6_All_DHCP_Relay_Agents_and_Servers, ctx->server_port, tnet_socket_type_udp_ipv6, &bestsource))){
+ TSK_DEBUG_WARN("Failed to get best source for [%s]:%u.", TNET_DHCP6_All_DHCP_Relay_Agents_and_Servers, ctx->server_port);
+ //fe80::21b:63ff:fea9:c14e%4
+ localsocket6 = tnet_socket_create(TNET_SOCKET_HOST_ANY, ctx->port_client, tnet_socket_type_udp_ipv6);
+ }
+ else{
+ localsocket6 = tnet_socket_create(bestsource, ctx->port_client, tnet_socket_type_udp_ipv6);
+ }
+
+ /* Check local socket. */
+ if(!TNET_SOCKET_IS_VALID(localsocket6)){
+ TSK_DEBUG_ERROR("Failed to create/bind DHCPv6 client socket.");
+ goto bail;
+ }
+
+ /* Always wait for 200ms before retransmission */
+ tv.tv_sec = 0;
+ tv.tv_usec = (200 * 1000);
+
+ if(tnet_sockaddr_init(TNET_DHCP6_All_DHCP_Relay_Agents_and_Servers, ctx->server_port, tnet_socket_type_udp_ipv6, &server)){
+ TNET_PRINT_LAST_ERROR("Failed to initialize the DHCPv6 server address.");
+ goto bail;
+ }
+
+ /* Set timeout */
+ timeout = tsk_time_epoch() + ctx->timeout;
+
+ do
+ {
+ tsk_list_foreach(item, ctx->interfaces){
+ iface = item->data;
+
+ /* Set FD */
+ FD_ZERO(&set);
+ FD_SET(localsocket6->fd, &set);
+
+ ///* ciaddr */
+ //if(request->type == dhcp_type_inform){
+ // struct sockaddr_storage ss;
+ // if(!tnet_get_sockaddr(localsocket4->fd, &ss)){
+ // uint32_t addr = tnet_htonl_2(&((struct sockaddr_in*)&ss)->sin_addr);
+ // memcpy(&request->ciaddr, &addr, 4);
+ // }
+ //}
+
+ ///* chaddr */
+ //memset(request->chaddr, 0, sizeof(request->chaddr));
+ //request->hlen = iface->mac_address_length > sizeof(request->chaddr) ? sizeof(request->chaddr) : iface->mac_address_length;
+ //memcpy(request->chaddr, iface->mac_address, request->hlen);
+
+ /* Serialize and send to the server. */
+ if(!(output = tnet_dhcp6_message_serialize(ctx, request))){
+ TSK_DEBUG_ERROR("Failed to serialize the DHCPv6 message.");
+ goto next_iface;
+ }
+ /* Send the request to the DHCP server */
+ if((ret =tnet_sockfd_sendto(localsocket6->fd, (const struct sockaddr*)&server, output->data, output->size))<0){
+ TNET_PRINT_LAST_ERROR("Failed to send DHCPv6 request.");
+
+ tsk_thread_sleep(150); // wait 150ms before trying the next iface.
+ goto next_iface;
+ }
+ /* wait for response */
+ if((ret = select(localsocket6->fd+1, &set, NULL, NULL, &tv))<0){ /* Error */
+ TNET_PRINT_LAST_ERROR("select have failed.");
+ tsk_thread_sleep(150); // wait 150ms before trying the next iface.
+ goto next_iface;
+ }
+ else if(ret == 0){ /* timeout ==> do nothing */
+ }
+ else{ /* there is data to read. */
+ unsigned int len = 0;
+ void* data = 0;
+
+ /* Check how how many bytes are pending */
+ if((ret = tnet_ioctlt(localsocket6->fd, FIONREAD, &len))<0){
+ goto next_iface;
+ }
+
+ /* Receive pending data */
+ data = tsk_calloc(len, sizeof(uint8_t));
+ if((ret = tnet_sockfd_recv(localsocket6->fd, data, len, 0))<0){
+ TSK_FREE(data);
+
+ TNET_PRINT_LAST_ERROR("Failed to receive DHCP dgrams.");
+ goto next_iface;
+ }
+
+ /* Parse the incoming response. */
+ reply = tnet_dhcp6_message_deserialize(ctx, data, (tsk_size_t)ret);
+ TSK_FREE(data);
+
+ if(reply)
+ { /* response successfuly parsed */
+ if(request->transaction_id != reply->transaction_id)
+ { /* Not same transaction id ==> continue*/
+ TSK_OBJECT_SAFE_FREE(reply);
+ }
+ }
+ }
+
+ next_iface:
+ TSK_OBJECT_SAFE_FREE(output);
+ if(reply){
+ goto bail;
+ }
+ }
+ break;//FIXME
+ }
+ while(timeout > tsk_time_epoch());
+
+bail:
+ TSK_OBJECT_SAFE_FREE(localsocket6);
+
+ return reply;
+}
+
+
+
+
+
+
+/**@ingroup tnet_dhcp6_group
+*/
+tnet_dhcp6_reply_t* tnet_dhcp6_requestinfo(const tnet_dhcp6_ctx_t* ctx, const tnet_dhcp6_option_orequest_t *orequest)
+{
+ tnet_dhcp6_reply_t* reply = 0;
+ tnet_dhcp6_request_t* request = tnet_dhcp6_request_create(dhcp6_type_information_request);
+ tnet_dhcp6_option_t* option = 0;
+
+ if(!ctx || !orequest || !request){
+ goto bail;
+ }
+
+ if((option = tnet_dhcp6_option_create(dhcp6_code_oro, orequest, sizeof(*orequest)))){
+ tsk_list_push_back_data(request->options, (void**)&option);
+ }
+
+ /* Vendor class */
+ {
+
+ }
+
+ reply = tnet_dhcp6_send_request(ctx, request);
+
+bail:
+
+ return reply;
+}
+
+
+
+
+
+//=================================================================================================
+// [[DHCPv6 CONTEXT]] object definition
+//
+static tsk_object_t* tnet_dhcp6_ctx_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_ctx_t *ctx = self;
+ if(ctx){
+ ctx->pen = TNET_IANA_PEN;
+ ctx->vendor_class_data = tsk_strdup(TNET_DHCP6_VENDOR_CLASS_DATA_DEFAULT);
+
+ ctx->port_client = TNET_DHCP6_CLIENT_PORT;
+ ctx->server_port = TNET_DHCP6_SERVER_PORT;
+ ctx->interfaces = tnet_get_interfaces();
+
+ ctx->timeout = 0xffff; /* FIXME */
+
+ if(!ctx->interfaces || TSK_LIST_IS_EMPTY(ctx->interfaces)){
+ TSK_DEBUG_ERROR("Failed to retrieve network interfaces.");
+ }
+
+ tsk_safeobj_init(ctx);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_ctx_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_ctx_t *ctx = self;
+ if(ctx){
+ tsk_safeobj_deinit(ctx);
+
+ TSK_FREE(ctx->vendor_class_data);
+
+ TSK_OBJECT_SAFE_FREE(ctx->interfaces);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_ctx_def_s =
+{
+ sizeof(tnet_dhcp6_ctx_t),
+ tnet_dhcp6_ctx_ctor,
+ tnet_dhcp6_ctx_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_ctx_def_t = &tnet_dhcp6_ctx_def_s;
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6.h b/tinyNET/src/dhcp6/tnet_dhcp6.h
new file mode 100644
index 0000000..156f5a9
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6.h
@@ -0,0 +1,128 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp6.h
+ * @brief Dynamic Host Configuration Protocol for IPv6 (DHCPv6) as per RFC 3315.
+ * Also implement: RFC 3319, 3633, 3646, 3736, 4242, 5007 ...
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef TNET_DHCP6_H
+#define TNET_DHCP6_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp6_message.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_object.h"
+#include "tsk_safeobj.h"
+
+TNET_BEGIN_DECLS
+
+#define TNET_DHCP6_VENDOR_CLASS_DATA_DEFAULT "doubango/v0.0.0"
+
+/** RFC 3315 - 5.1. Multicast Addresses
+* A link-scoped multicast address used by a client to communicate with
+* neighboring (i.e., on-link) relay agents and servers.
+* All servers and relay agents are members of this multicast group.
+*/
+#define TNET_DHCP6_All_DHCP_Relay_Agents_and_Servers "FF02::1:2"
+
+/** RFC 3315 - 5.1. Multicast Addresses
+* A site-scoped multicast address used by a relay agent to communicate with servers, either
+* because the relay agent wants to send messages to all servers or because it does not know the unicast
+* addresses of the servers. Note that in order for a relay agent to use this address, it must have an
+* address of sufficient scope to be reachable by the servers. All servers within the site are members of
+* this multicast group.
+*/
+#define TNET_DHCP6_All_DHCP_Servers "FF05::1:3"
+
+/*== RFC 3315 - 5.5. Transmission and Retransmission Parameters
+ * This section presents a table of values used to describe the message
+ * transmission behavior of clients and servers.
+*/
+#define TNET_DHCP6_RT_SOL_MAX_DELAY 1 /**< 1 sec Max delay of first Solicit */
+#define TNET_DHCP6_RT_SOL_TIMEOUT 1 /**< 1 sec Initial Solicit timeout */
+#define TNET_DHCP6_RT_SOL_MAX_RT 120 /**< 120 secs Max Solicit timeout value */
+#define TNET_DHCP6_RT_REQ_TIMEOUT 1 /**< 1 sec Initial Request timeout */
+#define TNET_DHCP6_RT_REQ_MAX_RT 30 /**< 30 secs Max Request timeout value */
+#define TNET_DHCP6_RT_REQ_MAX_RC 10 /**< 10 Max Request retry attempts */
+#define TNET_DHCP6_RT_CNF_MAX_DELAY 1 /**< 1 sec Max delay of first Confirm */
+#define TNET_DHCP6_RT_CNF_TIMEOUT 1 /**< 1 sec Initial Confirm timeout */
+#define TNET_DHCP6_RT_CNF_MAX_RT 4 /**< 4 secs Max Confirm timeout */
+#define TNET_DHCP6_RT_CNF_MAX_RD 10 /**< 10 secs Max Confirm duration */
+#define TNET_DHCP6_RT_REN_TIMEOUT 10 /**< 10 secs Initial Renew timeout */
+#define TNET_DHCP6_RT_REN_MAX_RT 600 /**< 600 secs Max Renew timeout value */
+#define TNET_DHCP6_RT_REB_TIMEOUT 10 /**< 10 secs Initial Rebind timeout */
+#define TNET_DHCP6_RT_REB_MAX_RT 600 /**< 600 secs Max Rebind timeout value */
+#define TNET_DHCP6_RT_INF_MAX_DELAY 1 /**< 1 sec Max delay of first Information-request */
+#define TNET_DHCP6_RT_INF_TIMEOUT 1 /**< 1 sec Initial Information-request timeout */
+#define TNET_DHCP6_RT_INF_MAX_RT 120 /**< 120 secs Max Information-request timeout value */
+#define TNET_DHCP6_RT_REL_TIMEOUT 1 /**< 1 sec Initial Release timeout */
+#define TNET_DHCP6_RT_REL_MAX_RC 5 /**< 5 MAX Release attempts */
+#define TNET_DHCP6_RT_DEC_TIMEOUT 1 /**< 1 sec Initial Decline timeout */
+#define TNET_DHCP6_RT_DEC_MAX_RC 5 /**< 5 Max Decline attempts */
+#define TNET_DHCP6_RT_REC_TIMEOUT 2 /**< 2 secs Initial Reconfigure timeout */
+#define TNET_DHCP6_RT_REC_MAX_RC 2 /**< 8 Max Reconfigure attempts */
+#define TNET_DHCP6_RT_HOP_COUNT_LIMIT 32 /**< 32 Max hop count in a Relay-forward message */
+
+/** RFC 3315 - 5.6 Representation of time values and "Infinity" as a time value */
+#define TNET_DHCP6_TIMEVAL_INFINITY 0XFFFFFFFF
+
+/**< Local port(client) to bind to for incoming DHCP messages as per RFC 3315 subclause 5.2. */
+#define TNET_DHCP6_CLIENT_PORT 546
+/**< Destination port(Server) for outgoing DHCP messages as per RFC 3315 subclause 5.2. */
+#define TNET_DHCP6_SERVER_PORT 547
+
+/**@ingroup tnet_dhcpv_group
+* DHCPv6 context.
+*/
+typedef struct tnet_dhcp6_ctx_s
+{
+ TSK_DECLARE_OBJECT;
+
+ uint16_t pen; /**< Private Enterprise Number assigned by the IANA. Default= @ref TNET_IANA_PEN.*/
+ char* vendor_class_data;
+
+ uint64_t timeout;
+
+ tnet_port_t port_client; /**< Local port to bind to for incloming DHCPv6 messages. Default: 546 */
+ tnet_port_t server_port; /**< Destination port for outgoing DHCPv6 messages. Default: 547 */
+ tnet_interfaces_L_t *interfaces;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_dhcp6_ctx_t;
+
+TINYNET_API tnet_dhcp6_reply_t* tnet_dhcp6_requestinfo(const tnet_dhcp6_ctx_t* ctx, const tnet_dhcp6_option_orequest_t *orequest);
+
+TINYNET_API tnet_dhcp6_ctx_t* tnet_dhcp6_ctx_create();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_ctx_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP6_H */
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_duid.c b/tinyNET/src/dhcp6/tnet_dhcp6_duid.c
new file mode 100644
index 0000000..38f2a52
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_duid.c
@@ -0,0 +1,288 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp6_duid.c
+ * @brief DHCPv6 (RFC 3315) DHCP Unique Identifier (DUID) as defined in subclause 9.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dhcp6_duid.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+int tnet_dhcp6_duid_llt_serialize(const tnet_dhcp6_duid_llt_t* self, tsk_buffer_t *output);
+int tnet_dhcp6_duid_en_serialize(const tnet_dhcp6_duid_en_t* self, tsk_buffer_t *output);
+int tnet_dhcp6_duid_ll_serialize(const tnet_dhcp6_duid_ll_t* self, tsk_buffer_t *output);
+
+
+tnet_dhcp6_duid_llt_t* tnet_dhcp6_duid_llt_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_duid_llt_def_t, payload, payload_size);
+}
+
+tnet_dhcp6_duid_en_t* tnet_dhcp6_duid_en_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_duid_en_def_t, payload, payload_size);
+}
+
+tnet_dhcp6_duid_ll_t* tnet_dhcp6_duid_ll_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_duid_ll_def_t, payload, payload_size);
+}
+
+int tnet_dhcp6_duid_init(tnet_dhcp6_duid_t *self, tnet_dhcp6_duid_type_t type)
+{
+ if(self){
+ if(!self->initialized){
+ self->type = type;
+ self->initialized = tsk_true;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+int tnet_dhcp6_duid_deinit(tnet_dhcp6_duid_t *self)
+{
+ if(self){
+ if(self->initialized){
+ self->initialized = tsk_true;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+tnet_dhcp6_duid_t* tnet_dhcp6_duid_deserialize(const void* data, tsk_size_t size)
+{
+ tnet_dhcp6_duid_t *duid = 0;
+ uint8_t* dataPtr = ((uint8_t*)data);
+ //uint8_t* dataEnd = (dataPtr+size);
+
+ tnet_dhcp6_duid_type_t type;
+ //uint8_t len = 0;
+
+ /* Check validity */
+ if(!dataPtr || size<2/*Type*/){
+ goto bail;
+ }
+
+ type = (tnet_dhcp6_duid_type_t) tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+
+bail:
+ return duid;
+}
+
+int tnet_dhcp6_duid_serialize(const tnet_dhcp6_duid_t* self, tsk_buffer_t *output)
+{
+ int ret = -1;
+
+ if(!self || !output){
+ return ret;
+ }
+
+ switch(self->type){
+ case dhcp6_duid_linklayer_plus_time:
+ {
+ ret = tnet_dhcp6_duid_llt_serialize(TNET_DHCP6_DUID_LLT(self), output);
+ break;
+ }
+
+ case dhcp6_duid_Vendor_assigned_id:
+ {
+ ret = tnet_dhcp6_duid_en_serialize(TNET_DHCP6_DUID_EN(self), output);
+ break;
+ }
+
+ case dhcp6_duid_linklayer:
+ {
+ ret = tnet_dhcp6_duid_ll_serialize(TNET_DHCP6_DUID_LL(self), output);
+ break;
+ }
+
+ default:
+ {
+ ret = -2;
+ goto bail;
+ }
+ }
+
+bail:
+ return ret;
+}
+
+/*=======================================================================================
+* RFC 3315 - 9.2. DUID Based on Link-layer Address Plus Time [DUID-LLT]
+*=======================================================================================*/
+
+int tnet_dhcp6_duid_llt_serialize(const tnet_dhcp6_duid_llt_t* self, tsk_buffer_t *output)
+{
+ return -1;
+}
+
+//
+// [[DHCPv6 DUID-LLT]] object definition
+//
+static tsk_object_t* tnet_dhcp6_duid_llt_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_duid_llt_t *duid = self;
+ if(duid){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dhcp6_duid_init(TNET_DHCP6_DUID(duid), dhcp6_duid_linklayer_plus_time);
+
+ if(payload && payload_size){
+ /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_duid_llt_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_duid_llt_t *duid = self;
+ if(duid){
+ /* deinit base */
+ tnet_dhcp6_duid_deinit(TNET_DHCP6_DUID(duid));
+
+ TSK_OBJECT_SAFE_FREE(duid->address);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_duid_llt_def_s =
+{
+ sizeof(tnet_dhcp6_duid_llt_t),
+ tnet_dhcp6_duid_llt_ctor,
+ tnet_dhcp6_duid_llt_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_duid_llt_def_t = &tnet_dhcp6_duid_llt_def_s;
+
+
+/*=======================================================================================
+* RFC 3315 - 9.3. DUID Assigned by Vendor Based on Enterprise Number [DUID-EN]
+*=======================================================================================*/
+
+int tnet_dhcp6_duid_en_serialize(const tnet_dhcp6_duid_en_t* self, tsk_buffer_t *output)
+{
+ return -1;
+}
+
+//
+// [[DHCPv6 DUID-EN]] object definition
+//
+static tsk_object_t* tnet_dhcp6_duid_en_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_duid_en_t *duid = self;
+ if(duid){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dhcp6_duid_init(TNET_DHCP6_DUID(duid), dhcp6_duid_Vendor_assigned_id);
+
+ if(payload && payload_size){
+ /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_duid_en_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_duid_en_t *duid = self;
+ if(duid){
+ /* deinit base */
+ tnet_dhcp6_duid_deinit(TNET_DHCP6_DUID(duid));
+
+ TSK_OBJECT_SAFE_FREE(duid->indentifier);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_duid_en_def_s =
+{
+ sizeof(tnet_dhcp6_duid_en_t),
+ tnet_dhcp6_duid_en_ctor,
+ tnet_dhcp6_duid_en_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_duid_en_def_t = &tnet_dhcp6_duid_en_def_s;
+
+
+/*=======================================================================================
+* RFC 3315 - 9.4. DUID Based on Link-layer Address [DUID-LL]
+*=======================================================================================*/
+
+int tnet_dhcp6_duid_ll_serialize(const tnet_dhcp6_duid_ll_t* self, tsk_buffer_t *output)
+{
+ return -1;
+}
+
+//
+// [[DHCPv6 DUID-LL]] object definition
+//
+static tsk_object_t* tnet_dhcp6_duid_ll_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_duid_ll_t *duid = self;
+ if(duid){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dhcp6_duid_init(TNET_DHCP6_DUID(duid), dhcp6_duid_linklayer);
+
+ if(payload && payload_size){
+ /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_duid_ll_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_duid_ll_t *duid = self;
+ if(duid){
+ /* deinit base */
+ tnet_dhcp6_duid_deinit(TNET_DHCP6_DUID(duid));
+
+ TSK_OBJECT_SAFE_FREE(duid->address);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_duid_ll_def_s =
+{
+ sizeof(tnet_dhcp6_duid_ll_t),
+ tnet_dhcp6_duid_ll_ctor,
+ tnet_dhcp6_duid_ll_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_duid_ll_def_t = &tnet_dhcp6_duid_ll_def_s;
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_duid.h b/tinyNET/src/dhcp6/tnet_dhcp6_duid.h
new file mode 100644
index 0000000..34383fa
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_duid.h
@@ -0,0 +1,185 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp6_duid.h
+ * @brief DHCPv6 (RFC 3315) DHCP Unique Identifier (DUID) as defined in subclause 9.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DHCP6_duid_H
+#define TNET_DHCP6_duid_H
+
+#include "tinynet_config.h"
+
+#include "tnet_hardwares.h"
+#include "tsk_list.h"
+#include "tsk_buffer.h"
+
+TNET_BEGIN_DECLS
+
+#define TNET_DHCP6_DUID(self) ((tnet_dhcp6_duid_t*)(self))
+#define TNET_DHCP6_DUID_LLT(self) ((tnet_dhcp6_duid_llt_t*)(self))
+#define TNET_DHCP6_DUID_EN(self) ((tnet_dhcp6_duid_en_t*)(self))
+#define TNET_DHCP6_DUID_LL(self) ((tnet_dhcp6_duid_ll_t*)(self))
+
+/** List of DHCPv6 DUIDs types as per RFC 3315 subclause 9.1.
+*/
+typedef enum tnet_dhcp6_duid_type_e
+{
+ dhcp6_duid_linklayer_plus_time = 1, /**< Link-layer address plus time. */
+ dhcp6_duid_Vendor_assigned_id = 2, /**< Vendor-assigned unique ID based on Enterprise Number. */
+ dhcp6_duid_linklayer = 3, /**< Link-layer address. */
+}
+tnet_dhcp6_duid_type_t;
+
+/** DHCP Unique Identifier (DUID) base class (subclause 9).
+*/
+typedef struct tnet_dhcp6_duid_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_bool_t initialized;
+
+ tnet_dhcp6_duid_type_t type; /* DUID type. 2-bytes value. */
+}
+tnet_dhcp6_duid_t;
+
+typedef tsk_list_t tnet_dhcp6_duids_L_t;
+
+#define TNET_DECLARE_DHCP6_DUID tnet_dhcp6_duid_t tnet_dhcp6_duid
+
+int tnet_dhcp6_duid_init(tnet_dhcp6_duid_t *self, tnet_dhcp6_duid_type_t type);
+int tnet_dhcp6_duid_deinit(tnet_dhcp6_duid_t *self);
+
+tnet_dhcp6_duid_t* tnet_dhcp6_duid_deserialize(const void* data, tsk_size_t size);
+int tnet_dhcp6_duid_serialize(const tnet_dhcp6_duid_t* self, tsk_buffer_t *output);
+
+/*=======================================================================================
+* RFC 3315 - 9.2. DUID Based on Link-layer Address Plus Time [DUID-LLT]
+*=======================================================================================*/
+
+/** DUID Based on Link-layer Address Plus Time [DUID-LLT]
+*/
+typedef struct tnet_dhcp6_duid_llt_s
+{
+ TNET_DECLARE_DHCP6_DUID;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 1 | hardware type (16 bits) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | time (32 bits) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ . .
+ . link-layer address (variable length) .
+ . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ /* The hardware type code as maintained by IANA. */
+ tnet_hardware_type_t htype;
+ /* The time value is the time that the DUID is generated represented in seconds
+ since midnight (UTC), January 1, 2000, modulo 2^32. */
+ uint32_t time;
+ /* The link-layer address. */
+ tsk_buffer_t *address;
+}
+tnet_dhcp6_duid_llt_t;
+
+
+/*=======================================================================================
+* RFC 3315 - 9.3. DUID Assigned by Vendor Based on Enterprise Number [DUID-EN]
+*=======================================================================================*/
+
+/** DUID Assigned by Vendor Based on Enterprise Number [DUID-EN]
+*/
+typedef struct tnet_dhcp6_duid_en_s
+{
+ TNET_DECLARE_DHCP6_DUID;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 2 | enterprise-number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | enterprise-number (contd) | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ . identifier .
+ . (variable length) .
+ . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ /* Tthe vendor's registered Private Enterprise Number as maintained by IANA.
+ For more information: http://www.iana.org/assignments/enterprise-numbers. */
+ uint32_t en;
+ /* The link-layer address. */
+ tsk_buffer_t *indentifier;
+}
+tnet_dhcp6_duid_en_t;
+
+/*=======================================================================================
+* RFC 3315 - 9.4. DUID Based on Link-layer Address [DUID-LL]
+*=======================================================================================*/
+
+/** DUID Based on Link-layer Address [DUID-LL]
+*/
+typedef struct tnet_dhcp6_duid_ll_s
+{
+ TNET_DECLARE_DHCP6_DUID;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 3 | hardware type (16 bits) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ . .
+ . link-layer address (variable length) .
+ . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ /* The hardware type code as maintained by IANA. */
+ tnet_hardware_type_t htype;
+ /* The link-layer address. */
+ tsk_buffer_t *address;
+}
+tnet_dhcp6_duid_ll_t;
+
+
+
+
+
+
+TINYNET_API tnet_dhcp6_duid_llt_t* tnet_dhcp6_duid_llt_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_duid_en_t* tnet_dhcp6_duid_en_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_duid_ll_t* tnet_dhcp6_duid_ll_create(const void* payload, tsk_size_t payload_size);
+
+
+
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_duid_llt_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_duid_en_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_duid_ll_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP6_duid_H */
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_message.c b/tinyNET/src/dhcp6/tnet_dhcp6_message.c
new file mode 100644
index 0000000..4691714
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_message.c
@@ -0,0 +1,131 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp6_message.c
+ * @brief DHCPv6 (RFC 3315) Messages.
+ */
+#include "tnet_dhcp6_message.h"
+#include "tnet_dhcp6.h"
+
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+tnet_dhcp6_message_t* tnet_dhcp6_message_create(tnet_dhcp6_message_type_t type)
+{
+ return tsk_object_new(tnet_dhcp6_message_def_t, type);
+}
+
+tnet_dhcp6_request_t* tnet_dhcp6_request_create(tnet_dhcp6_message_type_t type)
+{
+ return tnet_dhcp6_message_create(type);
+}
+
+tsk_buffer_t* tnet_dhcp6_message_serialize(const tnet_dhcp6_ctx_t *ctx, const tnet_dhcp6_message_t *self)
+{
+ tsk_buffer_t* output = 0;
+ //uint8_t _1byte;
+ uint16_t _2bytes;
+ uint32_t _4bytes;
+
+ /* Check message validity */
+ if (!self){
+ goto bail;
+ }
+
+ output = tsk_buffer_create_null();
+
+ /*== msg-type + transaction-id */
+ _4bytes = (((uint32_t)(self->type)) << 24) | (self->transaction_id & 0xFFFFFF);
+ _4bytes = tnet_ntohl(_4bytes);
+ tsk_buffer_append(output, &(_4bytes), 4);
+
+ /*== Vendor class
+ */
+ {
+ _2bytes = tnet_htons(dhcp6_code_vendor_class);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ _2bytes = tnet_htons((unsigned short)(4 + tsk_strlen(ctx->vendor_class_data)));
+ tsk_buffer_append(output, &(_2bytes), 2);
+ _4bytes = tnet_ntohl(ctx->pen);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ tsk_buffer_append(output, ctx->vendor_class_data, tsk_strlen(ctx->vendor_class_data));
+ }
+
+ /*== DHCP Options
+ */
+ {
+ tsk_list_item_t *item;
+ tnet_dhcp6_option_t* option;
+ tsk_list_foreach(item, self->options)
+ {
+ option = (tnet_dhcp6_option_t*)item->data;
+ if (tnet_dhcp6_option_serialize(option, output)){
+ TSK_DEBUG_WARN("Failed to serialize DHCPv6 OPTION (%u)", option->code);
+ }
+ }
+ }
+bail:
+ return output;
+}
+
+tnet_dhcp6_message_t* tnet_dhcp6_message_deserialize(const tnet_dhcp6_ctx_t *ctx, const uint8_t *data, tsk_size_t size)
+{
+ return 0;
+}
+
+
+
+//=================================================================================================
+// [[DHCPv6 MESSAGE]] object definition
+//
+static tsk_object_t* tnet_dhcp6_message_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_message_t *message = self;
+ if (message){
+ static uint16_t __dhcp6message_unique_tid = 0;//(uint32_t)tsk_time_epoch();
+
+ message->type = va_arg(*app, tnet_dhcp6_message_type_t);
+ message->transaction_id = ++__dhcp6message_unique_tid;
+ message->options = tsk_list_create();
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_message_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_message_t *message = self;
+ if (message){
+ TSK_OBJECT_SAFE_FREE(message->options);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_message_def_s =
+{
+ sizeof(tnet_dhcp6_message_t),
+ tnet_dhcp6_message_ctor,
+ tnet_dhcp6_message_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_message_def_t = &tnet_dhcp6_message_def_s;
+
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_message.h b/tinyNET/src/dhcp6/tnet_dhcp6_message.h
new file mode 100644
index 0000000..dc5d9d2
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_message.h
@@ -0,0 +1,143 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp6_message.h
+ * @brief DHCPv6 (RFC 3315) Messages.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DHCP6_MESSAGE_H
+#define TNET_DHCP6_MESSAGE_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp6_option.h"
+
+#include "tsk_object.h"
+
+TNET_BEGIN_DECLS
+
+struct tnet_dhcp6_ctx_s;
+
+/** List of all supported DHCPv6 messages.
+* For more info: RFC 3315 - 5.3. DHCP Message Types
+*/
+typedef enum tnet_dhcp6_message_type_e
+{
+ /* A client sends a Solicit message to locate servers. */
+ dhcp6_type_solicit = 1,
+ /* A server sends an Advertise message to indicate that it is available for DHCP service, in
+ response to a Solicit message received from a client. */
+ dhcp6_type_advertise = 2,
+ /* A client sends a Request message to request configuration parameters, including IP
+ addresses, from a specific server. */
+ dhcp6_type_request = 3,
+ /* A client sends a Confirm message to any available server to determine whether the
+ addresses it was assigned are still appropriate to the link to which the client is connected. */
+ dhcp6_type_confirm = 4,
+ /* A client sends a Renew message to the server that originally provided the client's addresses
+ and configuration parameters to extend the lifetimes on the addresses assigned to the
+ client and to update other configurationparameters. */
+ dhcp6_type_renew = 5,
+ /* A client sends a Rebind message to any available server to extend the lifetimes on the
+ addresses assigned to the client and to update other configuration parameters; this message is
+ sent after a client receives no response to a Renew message.*/
+ dhcp6_type_rebind = 6,
+ /* A server sends a Reply message containing assigned addresses and configuration parameters
+ in response to a Solicit, Request, Renew, Rebind message received from a client. A
+ server sends a Reply message containing configuration parameters in response to an
+ Information-request message. A server sends a Reply message in response to a Confirm message
+ confirming or denying that the addresses assigned to the client are appropriate to the
+ link to which the client is connected. A server sends a Reply message to acknowledge
+ receipt of a Release or Decline message.*/
+ dhcp6_type_reply = 7,
+ /* A client sends a Release message to the server that assigned addresses to the client to
+ indicate that the client will no longer use one or more of the assigned addresses.*/
+ dhcp6_type_release = 8,
+ /* A client sends a Decline message to a server to indicate that the client has determined that
+ one or more addresses assigned by the server are already in use on the link to which the
+ client is connected.*/
+ dhcp6_type_decline = 9,
+ /*A server sends a Reconfigure message to a client to inform the client that the server has
+ new or updated configuration parameters, and that the client is to initiate a Renew/Reply
+ or Information-request/Reply transaction with the server in order to receive the updatedinformation. */
+ dhcp6_type_reconfigure = 10,
+ /* A client sends an Information-request message to a server to request configuration
+ parameters without the assignment of any IP addresses to the client.*/
+ dhcp6_type_information_request = 11,
+ /* A relay agent sends a Relay-forward message to relay messages to servers, either directly
+ or through another relay agent. The received message, either a client message or a
+ Relay-forward message from another relay agent, is encapsulated in an option in the Relay-forward message.*/
+ dhcp6_type_relay_forw = 12,
+ /* A server sends a Relay-reply message to a relay agent containing a message that the relay
+ agent delivers to a client. The Relay-reply message may be relayed by other relay agents
+ for delivery to the destination relay agent.
+ The server encapsulates the client message as an option in the Relay-reply message, which the
+ relay agent extracts and relays to the client.*/
+ dhcp6_type_relay_repl = 13,
+}
+tnet_dhcp6_message_type_t;
+
+
+/** DHCPv6 message (common fields) as per RFC 3315 subclause 6.
+*/
+typedef struct tnet_dhcp6_message_s
+{
+ TSK_DECLARE_OBJECT;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | msg-type | transaction-id |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ . options .
+ . (variable) .
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ /* Identifies the DHCP message type. 1-byte value. */
+ tnet_dhcp6_message_type_t type;
+ /* The transaction ID for this message exchange. 3-bytes value. */
+ uint32_t transaction_id;
+ /* Options carried in this message. */
+ tnet_dhcp6_options_L_t *options;
+}
+tnet_dhcp6_message_t;
+
+typedef tsk_list_t tnet_dhcp6_messages_L_t;
+typedef tnet_dhcp6_message_t tnet_dhcp6_request_t;
+typedef tnet_dhcp6_message_t tnet_dhcp6_reply_t;
+
+tsk_buffer_t* tnet_dhcp6_message_serialize(const struct tnet_dhcp6_ctx_s *ctx, const tnet_dhcp6_message_t *self);
+tnet_dhcp6_message_t* tnet_dhcp6_message_deserialize(const struct tnet_dhcp6_ctx_s *ctx, const uint8_t *data, tsk_size_t size);
+
+TINYNET_API tnet_dhcp6_message_t* tnet_dhcp6_message_create(tnet_dhcp6_message_type_t type);
+TINYNET_API tnet_dhcp6_request_t* tnet_dhcp6_request_create(tnet_dhcp6_message_type_t type);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_message_def_t;
+
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP6_MESSAGE_H */
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_option.c b/tinyNET/src/dhcp6/tnet_dhcp6_option.c
new file mode 100644
index 0000000..91ec16a
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_option.c
@@ -0,0 +1,336 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp6_option.c
+ * @brief DHCPv6 Options as per RFC 3315 subclause 22.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dhcp6_option.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+
+#include <string.h>
+
+tnet_dhcp6_option_t* tnet_dhcp6_option_create(tnet_dhcp6_option_code_t code, const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_option_def_t, code, payload, payload_size);
+}
+
+tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_indentifer_create(tnet_dhcp6_option_code_t code, const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_option_identifier_def_t, code, payload, payload_size);
+}
+
+tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_clientid_create(const void* payload, tsk_size_t payload_size)
+{
+ return tnet_dhcp6_option_indentifer_create(dhcp6_code_clientid, payload, payload_size);
+}
+
+tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_serverid_create(const void* payload, tsk_size_t payload_size)
+{
+ return tnet_dhcp6_option_indentifer_create(dhcp6_code_serverid, payload, payload_size);
+}
+
+tnet_dhcp6_option_orequest_t* tnet_dhcp6_option_orequest_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_option_orequest_def_t, payload, payload_size);
+}
+
+tnet_dhcp6_option_orequest_t* tnet_dhcp6_option_orequest_create_null()
+{
+ return tnet_dhcp6_option_orequest_create(tsk_null, 0);
+}
+
+tnet_dhcp6_option_vendorclass_t* tnet_dhcp6_option_vendorclass_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_option_vendorclass_def_t, payload, payload_size);
+}
+
+tnet_dhcp6_option_vendorclass_t* tnet_dhcp6_option_vendorclass_create_null()
+{
+ return tnet_dhcp6_option_vendorclass_create(tsk_null, 0);
+}
+
+tnet_dhcp6_option_t* tnet_dhcp6_option_deserialize(const void* data, tsk_size_t size)
+{
+ tnet_dhcp6_option_t *option = 0;
+ uint8_t* dataPtr = ((uint8_t*)data);
+ //uint8_t* dataEnd = (dataPtr+size);
+
+ tnet_dhcp6_option_code_t code;
+ uint16_t len;
+
+ /* Check validity */
+ if(!dataPtr || size<4/*Code Len*/){
+ goto bail;
+ }
+
+ code = (tnet_dhcp6_option_code_t) tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+
+ len = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+
+ switch(code){
+ case dhcp6_code_clientid:
+ case dhcp6_code_serverid:
+ {
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+bail:
+ return option;
+}
+
+int tnet_dhcp6_option_serialize(const tnet_dhcp6_option_t* self, tsk_buffer_t *output)
+{
+ uint16_t _2bytes;
+ int ret = -1;
+
+ if(!self || !output){
+ goto bail;
+ }
+
+ /*== Code */
+ _2bytes = tnet_htons(self->code);
+ tsk_buffer_append(output, &(_2bytes), 2);
+
+ switch(self->code){
+ case dhcp6_code_clientid:
+ case dhcp6_code_serverid:
+ {
+ break;
+ }
+
+ case dhcp6_code_oro:
+ default:
+ {
+ if(self->data)
+ {
+ const tnet_dhcp6_option_orequest_t* opt = (const tnet_dhcp6_option_orequest_t*)self->data;
+ if(opt->codes){
+ /* option-len */
+ _2bytes = tnet_htons((unsigned short)opt->codes->size);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* option-data */
+ ret = tsk_buffer_append(output, opt->codes->data, opt->codes->size);
+ }
+
+ }
+ break;
+ }
+ }
+bail:
+ return ret;
+}
+
+int tnet_dhcp6_option_serializeex(tnet_dhcp6_option_code_t code, uint8_t length, const void* value, tsk_buffer_t *output)
+{
+ return -1;
+}
+
+//
+// [[DHCPv6 OPTION]] object definition
+//
+static tsk_object_t* tnet_dhcp6_option_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_option_t *option = self;
+ if(option){
+ tnet_dhcp6_option_code_t code = va_arg(*app, tnet_dhcp6_option_code_t);
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ option->code = code;
+ if(payload && payload_size){
+ if((option->data = (tnet_dhcp6_option_data_t*)tsk_calloc(payload_size, sizeof(uint8_t)))){
+ memcpy(option->data, payload, payload_size);
+ option->len = (uint16_t)payload_size;
+ }
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_option_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_option_t *option = self;
+ if(option){
+ TSK_OBJECT_SAFE_FREE(option->data);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_option_def_s =
+{
+ sizeof(tnet_dhcp6_option_t),
+ tnet_dhcp6_option_ctor,
+ tnet_dhcp6_option_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_option_def_t = &tnet_dhcp6_option_def_s;
+
+/*======================================================================================
+* RFC 3315 -
+ 22.2. Client Identifier Option
+ 22.3. Server Identifier Option
+*=======================================================================================*/
+//
+// [[DHCPv6 Option Request Option]] object definition
+//
+static tsk_object_t* tnet_dhcp6_option_identifier_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_option_identifier_t *option = self;
+ if(option){
+ //tnet_dhcp6_option_code_t code = va_arg(*app, tnet_dhcp6_option_code_t);
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size){
+ /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_option_identifier_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_option_identifier_t *option = self;
+ if(option){
+ TSK_OBJECT_SAFE_FREE(option->duid);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_option_identifier_def_s =
+{
+ sizeof(tnet_dhcp6_option_identifier_t),
+ tnet_dhcp6_option_identifier_ctor,
+ tnet_dhcp6_option_identifier_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_option_identifier_def_t = &tnet_dhcp6_option_identifier_def_s;
+
+/*======================================================================================
+* RFC 3315 - 22.7. Option Request Option
+*=======================================================================================*/
+
+int tnet_dhcp6_option_orequest_add_code(tnet_dhcp6_option_orequest_t* self, uint16_t code)
+{
+ uint16_t _2bytes;
+ int ret = -1;
+ if(self){
+ if(!self->codes){
+ if(!(self->codes = tsk_buffer_create_null())){
+ return -3;
+ }
+ }
+ _2bytes = tnet_ntohs(code);
+ if(!(ret = tsk_buffer_append(self->codes, &_2bytes, 2))){
+ TNET_DHCP6_OPTION(self)->len += 2;
+ }
+ }
+ return ret;
+}
+
+//
+// [[DHCPv6 Option Request Option]] object definition
+//
+static tsk_object_t* tnet_dhcp6_option_orequest_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_option_orequest_t *option = self;
+ if(option){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size)
+ { /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_option_orequest_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_option_orequest_t *option = self;
+ if(option){
+ TSK_OBJECT_SAFE_FREE(option->codes);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_option_orequest_def_s =
+{
+ sizeof(tnet_dhcp6_option_orequest_t),
+ tnet_dhcp6_option_orequest_ctor,
+ tnet_dhcp6_option_orequest_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_option_orequest_def_t = &tnet_dhcp6_option_orequest_def_s;
+
+/*======================================================================================
+* RFC 3315 - 22.16. Vendor Class Option
+*=======================================================================================*/
+
+//
+// [[DHCPv6 Option Request Option]] object definition
+//
+static tsk_object_t* tnet_dhcp6_option_vendorclass_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_option_vendorclass_t *option = self;
+ if(option){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size){
+ /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_option_vendorclass_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_option_vendorclass_t *option = self;
+ if(option){
+ TSK_OBJECT_SAFE_FREE(option->vendor_class_data);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_option_vendorclass_def_s =
+{
+ sizeof(tnet_dhcp6_option_vendorclass_t),
+ tnet_dhcp6_option_vendorclass_ctor,
+ tnet_dhcp6_option_vendorclass_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_option_vendorclass_def_t = &tnet_dhcp6_option_vendorclass_def_s;
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_option.h b/tinyNET/src/dhcp6/tnet_dhcp6_option.h
new file mode 100644
index 0000000..71241b9
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_option.h
@@ -0,0 +1,246 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dhcp6_option.h
+ * @brief DHCPv6 Options as per RFC 3315 subclause 22.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef TNET_DHCP6_OPTION_H
+#define TNET_DHCP6_OPTION_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp6_duid.h"
+
+#include "tsk_list.h"
+#include "tsk_buffer.h"
+
+TNET_BEGIN_DECLS
+
+#define TNET_DHCP6_OPTION(self) ((tnet_dhcp6_option_t*)(self))
+
+/** List of DHCPv6 option as registered by IANA (RFC 3315 subcaluse 24.3)*/
+typedef enum tnet_dhcp6_option_code_e
+{
+ dhcp6_code_clientid = 1, /**< Client Identifier Option. */
+ dhcp6_code_serverid = 2, /**< Server Identifier Option. */
+ dhcp6_code_ia_na = 3, /**< Identity Association for Non-temporary Addresses Option. */
+ dhcp6_code_ia_ta = 4, /**< Identity Association for Temporary Addresses Option. */
+ dhcp6_code_iaaddr = 5, /**< IA Address Option. */
+ dhcp6_code_oro = 6, /**< Option Request Option. */
+ dhcp6_code_preference = 7, /**< Preference Option. */
+ dhcp6_code_elapsed_time = 8, /**< Elapsed Time Option. */
+ dhcp6_code_relay_msg = 9, /**< Relay Message Option. */
+ dhcp6_code_auth = 11, /**< Authentication Option. */
+ dhcp6_code_unicast = 12, /**< Server Unicast Option. */
+ dhcp6_code_status_code = 13, /**< Status Code Option. */
+ dhcp6_code_rapid_commit = 14, /**< Rapid Commit Option. */
+ dhcp6_code_user_class = 15, /**< User Class Option. */
+ dhcp6_code_vendor_class = 16, /**< Vendor Class Option. */
+ dhcp6_code_vendor_opts = 17, /**< Vendor-specific Information Option. */
+ dhcp6_code_interface_id = 18, /**< Interface-Id Option. */
+ dhcp6_code_reconf_msg = 19, /**< Reconfigure Message Option. */
+ dhcp6_code_reconf_accept = 20, /**< Reconfigure Accept Option. */
+}
+tnet_dhcp6_option_code_t;
+
+/** List of DHCPv6 status codes as registered by IANA (RFC 3315 subclause 24.4) */
+typedef enum tnet_dhcp6_statuscode_e
+{
+ /* Success */
+ dhcp6_statuscode_Success = 0,
+ /* Failure, reason unspecified; this status code is sent by either a client
+ or a server to indicate a failure not explicitly specified in this document (RFC 3315). */
+ dhcp6_statuscode_UnspecFail = 1,
+ /* Server has no addresses available to assign to the IA(s). */
+ dhcp6_statuscode_NoAddrsAvail = 2,
+ /* Client record (binding) unavailable. */
+ dhcp6_statuscode_NoBinding = 3,
+ /* The prefix for the address is not appropriate for the link to which the client is attached. */
+ dhcp6_statuscode_NotOnLink = 4,
+ /* Sent by a server to a client to force the client to send messages to the server.
+ using the All_DHCP_Relay_Agents_and_Servers address.*/
+ dhcp6_statuscode_UseMulticast = 5
+}
+tnet_dhcp6_statuscode_t;
+
+/*=======================================================================================
+* RFC 3315 - 22.1. Format of DHCP Options
+*=======================================================================================*/
+
+/**@ingroup tnet_dhcpv_group
+* DHCPv6 option-data.
+*/
+typedef struct tnet_dhcp6_option_data_s
+{
+ TSK_DECLARE_OBJECT;
+}
+tnet_dhcp6_option_data_t;
+#define TNET_DECLARE_DHCP6_OPTION_DATA tnet_dhcp6_option_data_t dhcp6_option_data
+
+typedef struct tnet_dhcp6_option_s
+{
+ TSK_DECLARE_OBJECT;
+
+ /* RFC 3315 - 22.1. Format of DHCP Options
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | option-code(2) | option-len(2) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | option-data |
+ | (option-len octets) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ /* An unsigned integer identifying the specific option type carried in this option.*/
+ tnet_dhcp6_option_code_t code;
+ /* Option length. Same as tsk_strlen(data buffer)*/
+ uint16_t len;
+ /* opton-data */
+ tnet_dhcp6_option_data_t *data;
+}
+tnet_dhcp6_option_t;
+
+typedef tsk_list_t tnet_dhcp6_options_L_t;
+
+#define TNET_DECLARE_DHCP6_OPTION tnet_dhcp6_option_t dhcp6_option
+
+tnet_dhcp6_option_t* tnet_dhcp6_option_deserialize(const void* data, tsk_size_t size);
+int tnet_dhcp6_option_serialize(const tnet_dhcp6_option_t* self, tsk_buffer_t *output);
+int tnet_dhcp6_option_serializeex(tnet_dhcp6_option_code_t code, uint8_t length, const void* value, tsk_buffer_t *output);
+
+
+
+
+/*======================================================================================
+* RFC 3315 -
+ 22.2. Client Identifier Option
+ 22.3. Server Identifier Option
+*=======================================================================================*/
+/** DHCPv6 Client /server Identifier Option (subclause 22.2 and 22.3).
+*/
+typedef struct tnet_dhcp6_option_identifier_s
+{
+ TNET_DECLARE_DHCP6_OPTION_DATA;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | OPTION_XXXXXXID | option-len |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ . .
+ . DUID .
+ . (variable length) .
+ . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ OPTION_XXXXXXID = OPTION_CLIENTID or OPTION_SERVERID
+ */
+ tnet_dhcp6_duid_t *duid;
+}
+tnet_dhcp6_option_identifier_t;
+typedef tnet_dhcp6_option_identifier_t tnet_dhcp6_option_clientid_t;
+typedef tnet_dhcp6_option_identifier_t tnet_dhcp6_option_serverid_t;
+
+
+/*======================================================================================
+* RFC 3315 - 22.4. Identity Association for Non-temporary Addresses Option
+*=======================================================================================*/
+
+/*======================================================================================
+* RFC 3315 - 22.7. Option Request Option
+*=======================================================================================*/
+
+/** DHCPv6 Option Request Option (subclause 22.7).
+*/
+typedef struct tnet_dhcp6_option_orequest_s
+{
+ TNET_DECLARE_DHCP6_OPTION_DATA;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | OPTION_ORO | option-len |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | requested-option-code-1 | requested-option-code-2 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ... |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ tsk_buffer_t* codes;
+}
+tnet_dhcp6_option_orequest_t;
+
+TINYNET_API int tnet_dhcp6_option_orequest_add_code(tnet_dhcp6_option_orequest_t* self, uint16_t code);
+
+/*======================================================================================
+* RFC 3315 - 22.16. Vendor Class Option
+*=======================================================================================*/
+
+/** DHCPv6 Vendor Class Option (subclause 22.16).
+*/
+typedef struct tnet_dhcp6_option_vendorclass_s
+{
+ TNET_DECLARE_DHCP6_OPTION_DATA;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | OPTION_VENDOR_CLASS | option-len |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | enterprise-number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ . .
+ . vendor-class-data .
+ . . . . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ uint32_t enterprise_number;
+ /*
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+
+ | vendor-class-len | opaque-data |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+
+ */
+ tsk_buffer_t* vendor_class_data;
+}
+tnet_dhcp6_option_vendorclass_t;
+
+
+TINYNET_API tnet_dhcp6_option_t* tnet_dhcp6_option_create(tnet_dhcp6_option_code_t code, const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_indentifer_create(tnet_dhcp6_option_code_t code, const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_clientid_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_serverid_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_orequest_t* tnet_dhcp6_option_orequest_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_orequest_t* tnet_dhcp6_option_orequest_create_null();
+TINYNET_API tnet_dhcp6_option_vendorclass_t* tnet_dhcp6_option_vendorclass_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_vendorclass_t* tnet_dhcp6_option_vendorclass_create_null();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_option_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_option_identifier_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_option_orequest_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_option_vendorclass_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP6_OPTION_H */
diff --git a/tinyNET/src/dns/tnet_dns.c b/tinyNET/src/dns/tnet_dns.c
new file mode 100644
index 0000000..87cd9b5
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns.c
@@ -0,0 +1,967 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns.c
+ * @brief DNS utility functions (RFCS [1034 1035] [3401 3402 3403 3404] [3761]).
+ *
+ */
+#include "tnet_dns.h"
+
+#include "tnet_dns_regexp.h"
+#include "tnet_dns_message.h"
+#include "tnet_dns_opt.h"
+#include "tnet_dns_srv.h"
+#include "tnet_dns_naptr.h"
+
+#include "tnet_types.h"
+
+#include "tsk_memory.h"
+#include "tsk_time.h"
+#include "tsk_debug.h"
+#include "tsk_string.h"
+
+#include <string.h> /* tsk_strlen, memser, .... */
+#include <ctype.h> /* isdigist */
+
+/* DNS cache functions */
+int tnet_dns_cache_maintenance(tnet_dns_ctx_t *ctx);
+int tnet_dns_cache_entry_add(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t* response);
+const tnet_dns_cache_entry_t* tnet_dns_cache_entry_get(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype);
+
+/**@defgroup tnet_dns_group DNS utility functions (RFCS [1034 1035] [3401 3402 3403 3404]).
+*
+* <h1>11 DNS</h1>
+* <p>
+* The DNS Stack (RFC 1034 and RFC 1035) contains all network functions to send queries (both IPv4 and IPv6) and parse responses. <br>
+* The core framework implements RFC 3401, 3402, 3403 and 3404, also known as Dynamic Delegation Discovery System (DDDS).
+* </p>
+* <p>
+* The DNS servers are automatically loaded by the stack when you create a context (@ref tnet_dns_ctx_create()). <br>
+* On Windows systems (XP, VISTA, 7 and CE) the servers are retrieved using WIN32 APIs. On Unix-like systems (both desktop and embedded) such as Debian, Ubuntu, Nokia’s N900… the list of DNS servers comes from “/etc/resolv.conf” file. <br>
+* On Google Android operating system, this file is missing and the DNS settings are stored in the shared memory. You can access this shared memory by using @a property_get() and @a property_set() function which are part of Bionic. <br>
+* In all cases, you can retrieve the DNS servers yourself (e.g. using java/C# Frameworks) and add them to the context using @ref tnet_dns_add_server().
+* </p>
+* <p>
+* DNS resolution is always performed in a synchronous manner and is thread-safe. For all DNS requests the default timeout value is 5 seconds (@ref TNET_DNS_TIMEOUT_DEFAULT).
+* The stack also implements the ENUM protocol (RFC 3761).
+* </p>
+*
+* <h2>11.1 Resource Records</h2>
+* The table below lists all DNS Resource Records (RR) for which we provide a parser.
+*
+* <table>
+* <tr><td>Code</td> <td>RFC</td> <td>Description</td> <td>Well-defined type</td></tr>
+* <tr><td>A</td> <td>RFC 1035</td> <td>IPv4 address</td> <td>tnet_dns_a_t</td></tr>
+* <tr><td>AAAA</td> <td>RFC 3596</td> <td>IPv6 address</td> <td>tnet_dns_aaaa_t</td></tr>
+* <tr><td>CNAME</td> <td>RFC 1035</td> <td>Canonical name</td> <td>tnet_dns_cname_t</td></tr>
+* <tr><td>MX</td> <td>RFC 2035</td> <td>Mail exchange</td> <td>tnet_dns_mx_t</td></tr>
+* <tr><td>NAPTR</td> <td>RFC 3403</td> <td>Naming Authority Pointer</td> <td>tnet_dns_naptr_t</td></tr>
+* <tr><td>NS</td> <td>RFC 1035</td> <td>Name Server</td> <td>tnet_dns_ns_t</td></tr>
+* <tr><td>OPT</td> <td>RFC 2671</td> <td>Option</td> <td>tnet_dns_opt_t</td></tr>
+* <tr><td>PTR</td> <td>RFC 1035</td> <td>Pointer record</td> <td>tnet_dns_ptr_t</td></tr>
+* <tr><td>SOA</td> <td>RFC1035</td> <td>Start Of Authority record</td> <td>tnet_dns_soa_t</td></tr>
+* <tr><td>SRV</td> <td>RFC 2782</td> <td>Service locator</td> <td>tnet_dns_srv_t</td></tr>
+* </table>
+*
+* Here is an example of how to use the DNS stack to perform DNS NAPTR resolution and print the result to the console.
+*
+* @code
+tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+tnet_dns_response_t *response = tsk_null;
+const tsk_list_item_t* item;
+const tnet_dns_rr_t* rr;
+
+if((response = tnet_dns_resolve(ctx, "sip2sip.info", qclass_in, qtype_naptr)))
+{
+if(TNET_DNS_RESPONSE_IS_SUCCESS(response)){
+TSK_DEBUG_INFO("We got a success response from the DNS server.");
+// loop through the answers
+tsk_list_foreach(item, response->Answers){
+rr = item->data;
+if(rr->qtype == qtype_naptr){
+const tnet_dns_naptr_t *naptr = (const tnet_dns_naptr_t*)rr;
+
+TSK_DEBUG_INFO("order=%u pref=%u flags=%s services=%s regexp=%s replacement=%s",
+naptr->order,
+naptr->preference,
+naptr->flags,
+naptr->services,
+naptr->regexp,
+naptr->replacement);
+}
+}
+}
+else{
+TSK_DEBUG_ERROR("We got an error response from the DNS server. Error code: %u", response->Header.RCODE);
+}
+}
+
+TSK_OBJECT_SAFE_FREE(response);
+TSK_OBJECT_SAFE_FREE(ctx);
+
+* @endcode
+* The @a ctx could be used several times and is a well-defined object.<br>
+* The console will output:
+* <i>INFO: We got a success response from the DNS server.</i><br>
+* <i>INFO: order=10 pref=0 flags=S services=SIP+d2u regexp=(null) replacement=_sip._udp.sip2sip.info</i><br>
+*
+* <h2>11.2 ENUM</h2>
+* ENUM (E.164 Number Mapping) protocol has been defined in RFC 3761.
+* ENUM protocol is used to transform telephone numbers of the PSTN network (e.g. +33600000) into internet resource addresses (e.g. sip:diopmamadou@example.com) by using DNS lookup (NAPTR). The internet resource address could be an email, ICQ, IAX2, H.323 …
+* In our case (3GPP IMS) it is typically used to convert TEL URIs (e.g. tel:+33600000) into SIP URIs (sip:+33600000;user=phone). The telephone number to convert should be a valid E.164 number.
+*
+* <h3>11.2.1 Usage</h3>
+* The code below shows how to gets the SIP address (with the higher order) associated to an E.164 telephone number.
+*
+* @code
+tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+tnet_dns_response_t* response = tsk_null;
+char* uri = tsk_null;
+
+if((uri = tnet_dns_enum_2(ctx, "E2U+SIP", "+1-800-555-5555","e164.org"))){
+TSK_DEBUG_INFO("URI=%s", uri);
+TSK_FREE(uri);
+}
+else{
+TSK_DEBUG_ERROR("ENUM(%s) failed", "+1-800-555-5555");
+}
+
+TSK_OBJECT_SAFE_FREE(response);
+TSK_OBJECT_SAFE_FREE(ctx);
+* @endcode
+*
+* Console Output:<br>
+* <i>INFO: URI=sip:16416418000-555-5555@sip.tollfreegateway.com</i><br>
+*
+* E2U+SIP is the name of SIP ENUM service assigned by the IANA. Any assigned service () could be used even if the associated addresse type isn’t a well-knonw internet address.
+* To get all internet addresses (email, IAX2, ICQ, H.323 …) associated to the telephone, use @ref tnet_dns_enum() instead of @ref tnet_dns_enum_2().
+*/
+
+/**@ingroup tnet_dns_group
+* Creates new DNS context.
+*/
+tnet_dns_ctx_t* tnet_dns_ctx_create()
+{
+ return tsk_object_new(tnet_dns_ctx_def_t);
+}
+
+/**@ingroup tnet_dns_group
+* Creates new DNS cache entry.
+*/
+tnet_dns_cache_entry_t* tnet_dns_cache_entry_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t* answer)
+{
+ return tsk_object_new(tnet_dns_cache_entry_def_t, qname, qclass, qtype, answer);
+}
+
+
+/**@ingroup tnet_dns_group
+* Cleanup the internal DNS cache.
+* @param ctx The DNS context containing the cache to cleanup.
+* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
+* @retval Zero if succeeed and non-zero error code otherwise.
+*/
+int tnet_dns_cache_clear(tnet_dns_ctx_t* ctx)
+{
+ if (ctx){
+ tsk_safeobj_lock(ctx);
+ tsk_list_clear_items(ctx->cache);
+ tsk_safeobj_unlock(ctx);
+
+ return 0;
+ }
+ return -1;
+}
+
+/**@ingroup tnet_dns_group
+* Sends DNS request over the network. The request will be sent each 500 milliseconds until @ref TNET_DNS_TIMEOUT_DEFAULT milliseconds is reached.
+* @param ctx The DNS context to use. The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
+* @param qname The domain name (e.g. google.com).
+* @param qclass The CLASS of the query.
+* @param qtype The type of the query.
+* @retval The DNS response. The @a answers in the @a response are already filtered.
+* MUST be destroyed using @a TSK_OBJECT_SAFE_FREE() macro.
+* @sa @ref tnet_dns_query_srv, @ref tnet_dns_query_naptr_srv, @ref tnet_dns_enum.
+*
+* @code
+* tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+* tnet_dns_response_t *response = tnet_dns_resolve(ctx, "sip2sip.info", qclass_in, qtype_srv);
+* TSK_OBJECT_SAFE_FREE(response);
+* TSK_OBJECT_SAFE_FREE(ctx);
+* @endcode
+*/
+tnet_dns_response_t *tnet_dns_resolve(tnet_dns_ctx_t* ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)
+{
+#if HAVE_DNS_H
+ struct sockaddr_storage result;
+ struct sockaddr *from;
+ uint32_t fromlen;
+ char buf[TNET_DNS_DGRAM_SIZE_DEFAULT];
+ int32_t ret;
+
+ tnet_dns_response_t *response = tsk_null;
+
+ tnet_socket_t *localsocket4 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv4);
+ tnet_socket_t *localsocket6 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv6);
+
+ tsk_safeobj_lock(ctx);
+
+ // First, try with IPv4
+ if(TNET_SOCKET_IS_VALID(localsocket4)){
+ if((ret = tnet_getsockname(localsocket4->fd, &result))){
+ TNET_PRINT_LAST_ERROR("tnet_getsockname() failed.");
+ goto ipv6;
+ }
+ from = (struct sockaddr *) &result;
+ fromlen = tnet_get_sockaddr_size(from);
+
+ if ((ret = dns_search(ctx->resolv_handle, qname, qclass, qtype, buf, TNET_DNS_DGRAM_SIZE_DEFAULT, from, &fromlen)) > 0) {
+ response = tnet_dns_message_deserialize((uint8_t *) buf, ret);
+ goto done;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("dns_search_v4()");
+ }
+ }
+ipv6:
+ // Then, try with IPv6
+ if(TNET_SOCKET_IS_VALID(localsocket6)){
+ if((ret = tnet_getsockname(localsocket6->fd, &result))){
+ TNET_PRINT_LAST_ERROR("tnet_getsockname() failed.");
+ goto done;
+ }
+ from = (struct sockaddr *) &result;
+ fromlen = tnet_get_sockaddr_size(from);
+
+ if((ret = dns_search(ctx->resolv_handle, qname, qclass, qtype, buf, TNET_DNS_DGRAM_SIZE_DEFAULT, from, &fromlen)) > 0){
+ response = tnet_dns_message_deserialize((uint8_t *) buf, ret);
+ goto done;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("dns_search_v6()");
+ }
+ }
+
+done:
+ tsk_safeobj_unlock(ctx);
+
+ TSK_OBJECT_SAFE_FREE(localsocket4);
+ TSK_OBJECT_SAFE_FREE(localsocket6);
+
+ return response;
+#else
+ tsk_buffer_t *output = tsk_null;
+ tnet_dns_query_t* query = tnet_dns_query_create(qname, qclass, qtype);
+ tnet_dns_response_t *response = tsk_null;
+ tsk_bool_t from_cache = tsk_false;
+
+ /* Check validity */
+ if (!ctx || !query){
+ goto bail;
+ }
+
+ /* Is there any DNS Server? */
+ if (TSK_LIST_IS_EMPTY(ctx->servers)){
+ TSK_DEBUG_ERROR("Failed to load DNS Servers. You can add new DNS servers by using \"tnet_dns_add_server\".");
+ goto bail;
+ }
+
+ /* Cache maintenance */
+ if (!TSK_LIST_IS_EMPTY(ctx->cache)){
+ /* Only do maintenance if the cache is not empty */
+ tnet_dns_cache_maintenance(ctx);
+ }
+
+ /* Retrieve data from cache. */
+ if (ctx->caching){
+ const tnet_dns_cache_entry_t *entry = tnet_dns_cache_entry_get(ctx, qname, qclass, qtype);
+ if (entry){
+ response = tsk_object_ref(((tnet_dns_cache_entry_t*)entry)->response);
+ from_cache = tsk_true;
+ goto bail;
+ }
+ }
+
+ /* Set user preference */
+ query->Header.RD = ctx->recursion;
+
+ /* EDNS0 */
+ if (ctx->edns0){
+ tnet_dns_opt_t *rr_opt = tnet_dns_opt_create(TNET_DNS_DGRAM_SIZE_DEFAULT);
+ if (!query->Additionals){
+ query->Additionals = tsk_list_create();
+ }
+ tsk_list_push_back_data(query->Additionals, (void**)&rr_opt);
+ query->Header.ARCOUNT++;
+ }
+
+ /* Serialize and send to the server. */
+ if (!(output = tnet_dns_message_serialize(query))){
+ TSK_DEBUG_ERROR("Failed to serialize the DNS message.");
+ goto bail;
+ }
+
+ /* ============================ */
+ // Send and Recaive data
+ /* ============================ */
+ {
+ int ret = -1;
+ struct timeval tv;
+ fd_set set;
+ tnet_fd_t maxFD;
+ uint64_t timeout = 0;
+ tsk_list_item_t *item;
+ const tnet_address_t *address;
+ struct sockaddr_storage server;
+ tnet_socket_t *localsocket4 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv4);
+ tnet_socket_t *localsocket6 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv6);
+ tsk_bool_t useIPv6 = TNET_SOCKET_IS_VALID(localsocket6);
+
+ tsk_safeobj_lock(ctx);
+
+ /* Check socket validity */
+ if (!TNET_SOCKET_IS_VALID(localsocket4)){
+ goto done;
+ }
+
+ /* Always wait 500ms before retransmission */
+ tv.tv_sec = 0;
+ tv.tv_usec = (500 * 1000);
+
+ do
+ {
+ //
+ // Send data (loop through all intefaces)
+ //
+ tsk_list_foreach(item, ctx->servers)
+ {
+ address = item->data;
+ if (!address->ip ||
+ (address->family != AF_INET && address->family != AF_INET6) ||
+ (address->family == AF_INET6 && !TNET_SOCKET_IS_VALID(localsocket6))){
+ continue;
+ }
+
+ if (tnet_sockaddr_init(address->ip, ctx->server_port, (address->family == AF_INET ? tnet_socket_type_udp_ipv4 : tnet_socket_type_udp_ipv6), &server)){
+ TSK_DEBUG_ERROR("Failed to initialize the DNS server address: \"%s\"", address->ip);
+ continue;
+ }
+
+ TSK_DEBUG_INFO("Sending DNS query to \"%s\"", address->ip);
+
+ if (address->family == AF_INET6){
+ if ((ret = tnet_sockfd_sendto(localsocket6->fd, (const struct sockaddr*)&server, output->data, output->size))){
+ // succeed?
+ break;
+ }
+ }
+ else{
+ if ((ret = tnet_sockfd_sendto(localsocket4->fd, (const struct sockaddr*)&server, output->data, output->size))){
+ // succeed?
+ break;
+ }
+ }
+ }
+
+ //
+ // Received data
+ //
+ /* First time? ==> set timeout value */
+ if (!timeout){
+ timeout = tsk_time_epoch() + ctx->timeout;
+ }
+
+ /* Set FDs */
+ FD_ZERO(&set);
+ FD_SET(localsocket4->fd, &set);
+ if (useIPv6){
+ FD_SET(localsocket6->fd, &set);
+ maxFD = TSK_MAX(localsocket4->fd, localsocket6->fd);
+ }
+ else{
+ maxFD = localsocket4->fd;
+ }
+
+ /* wait for response */
+ if ((ret = select(maxFD + 1, &set, NULL, NULL, &tv)) < 0){ /* Error */
+ TNET_PRINT_LAST_ERROR("Select failed.");
+ goto done;
+ }
+ else if (ret == 0){ /* timeout ==> do nothing */
+
+ }
+ else{ /* there is data to read */
+ unsigned int len = 0;
+ void* data = 0;
+ tnet_fd_t active_fd;
+
+ /* Find active file descriptor */
+ if (FD_ISSET(localsocket4->fd, &set)){
+ active_fd = localsocket4->fd;
+ }
+ else if (FD_ISSET(localsocket6->fd, &set)){
+ active_fd = localsocket4->fd;
+ }
+ else{
+ TSK_DEBUG_ERROR("FD_ISSET ==> Invalid file descriptor.");
+ continue;
+ }
+
+ /* Check how how many bytes are pending */
+ if ((ret = tnet_ioctlt(active_fd, FIONREAD, &len)) < 0){
+ TSK_DEBUG_ERROR("tnet_ioctlt failed with error code:%d", tnet_geterrno());
+ goto done;
+ }
+
+ /* Receive pending data */
+ data = tsk_calloc(len, sizeof(uint8_t));
+ if ((ret = tnet_sockfd_recv(active_fd, data, len, 0)) < 0){
+ TSK_FREE(data);
+
+ TSK_DEBUG_ERROR("tnet_sockfd_recv failed with error code:%d", tnet_geterrno());
+ goto done;
+ }
+
+ /* Parse the incoming response. */
+ response = tnet_dns_message_deserialize(data, (tsk_size_t)ret);
+ TSK_FREE(data);
+
+ if (response)
+ { /* response successfuly parsed */
+ if (query->Header.ID != response->Header.ID || !TNET_DNS_MESSAGE_IS_RESPONSE(response)){
+ /* Not same transaction id ==> continue*/
+ TSK_OBJECT_SAFE_FREE(response);
+ }
+ else goto done;
+ }
+ }
+ } while (timeout > tsk_time_epoch());
+
+ done:
+ tsk_safeobj_unlock(ctx);
+
+ TSK_OBJECT_SAFE_FREE(localsocket4);
+ TSK_OBJECT_SAFE_FREE(localsocket6);
+ goto bail;
+ }
+
+
+bail:
+ TSK_OBJECT_SAFE_FREE(query);
+ TSK_OBJECT_SAFE_FREE(output);
+
+ /* Add the result to the cache. */
+ if (response){
+ if (!from_cache && ctx->caching){
+ tnet_dns_cache_entry_add(ctx, qname, qclass, qtype, response);
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to contact the DNS server.");
+ }
+
+ return response;
+#endif
+}
+
+/**@ingroup tnet_dns_group
+* Gets list of URIs associated to this telephone number by using ENUM protocol (RFC 3761).
+* @param ctx The DNS context.
+* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
+* @param e164num A valid E.164 number (e.g. +1-800-555-5555).
+* @param domain The domain name (e.g e164.arpa, e164.org, ...). If Null, default value is "e164.arpa" (IANA).
+* @retval The DNS response with NAPTR RRs. The @a answers in the @a response are already filtered.
+* MUST be destroyed using @a TSK_OBJECT_SAFE_FREE macro.
+* @sa @ref tnet_dns_resolve, @ref tnet_dns_enum_2.
+*/
+tnet_dns_response_t* tnet_dns_enum(tnet_dns_ctx_t* ctx, const char* e164num, const char* domain)
+{
+ char e164domain[255];
+ tnet_dns_response_t* ret = tsk_null;
+ int e164size;
+ int i, j; // must be signed
+
+ e164size = (int)tsk_strlen(e164num);
+
+ if (!ctx || !e164num || !e164size){
+ goto bail;
+ }
+
+ if (e164size /* max=15 digits + ".e164.arpa" + '+' */ >= (sizeof(e164domain) - 1)){
+ TSK_DEBUG_ERROR("%s is an invalid E.164 number.", e164num);
+ goto bail;
+ }
+
+ memset(e164domain, '\0', sizeof(e164domain));
+
+ /* RFC 3761 - 2.4. Valid Databases
+ 1. Remove all characters with the exception of the digits. For
+ example, the First Well Known Rule produced the Key
+ "+442079460148". This step would simply remove the leading "+",
+ producing "442079460148".
+
+ 2. Put dots (".") between each digit. Example:
+ 4.4.2.0.7.9.4.6.0.1.4.8
+
+ 3. Reverse the order of the digits. Example:
+ 8.4.1.0.6.4.9.7.0.2.4.4
+
+ 4. Append the string ".e164.arpa" to the end. Example:
+ 8.4.1.0.6.4.9.7.0.2.4.4.e164.arpa
+
+ This domain-name is used to request NAPTR records which may contain
+ the end result or, if the flags field is blank, produces new keys in
+ the form of domain-names from the DNS.
+ */
+ for (i = e164size - 1, j = 0; i >= 0; i--){
+ if (!isdigit(e164num[i])){
+ continue;
+ }
+ e164domain[j++] = e164num[i];
+ e164domain[j++] = '.';
+ }
+
+ // append domain name
+ if (domain){
+ memcpy(&e164domain[j], domain, ((tsk_strlen(domain) + j) >= sizeof(e164domain) - 1) ? (sizeof(e164domain) - j - 1) : tsk_strlen(domain));
+ }
+ else{
+ memcpy(&e164domain[j], "e164.arpa", 9);
+ }
+
+ /* == Performs DNS (NAPTR) lookup == */
+ ret = tnet_dns_resolve(ctx, e164domain, qclass_in, qtype_naptr);
+
+bail:
+
+ return ret;
+}
+
+/**@ingroup tnet_dns_group
+* Gets the internate address associated to this telephone number by using ENUM protocol (RFC 3761).
+* Only terminale rules containing uris(flags="u") will be considered and the regex string will be executed on the original string for
+* substitution. <br>
+* <b> Parsing complex regexp will probably fail (99.99% chance). Please use @ref tnet_dns_enum if you want to use your own regexp parser. </b>
+* @param ctx The DNS context.
+* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
+* @param service The ENUM service (e.g. E2U+SIP).
+* @param e164num A valid E.164 number (e.g. +1-800-555-5555).
+* @param domain The domain name (e.g e164.arpa, e164.org, ...). If Null, default value is "e164.arpa" (IANA).
+* @retval The Internet address (SIP, email, ICQ, fax, ...) associated to this service.
+* MUST be freed using @a TSK_FREE macro.
+* @sa @ref tnet_dns_resolve, @ref tnet_dns_enum.
+*/
+char* tnet_dns_enum_2(tnet_dns_ctx_t* ctx, const char* service, const char* e164num, const char* domain)
+{
+ tnet_dns_response_t* response;
+ const tsk_list_item_t* item;
+ char* ret = tsk_null;
+ const tnet_dns_rr_t* rr;
+
+ if ((response = tnet_dns_enum(ctx, e164num, domain))){
+ if (TNET_DNS_RESPONSE_IS_SUCCESS(response)){
+ tsk_list_foreach(item, response->Answers){
+ rr = item->data;
+ if (rr->qtype == qtype_naptr){
+ const tnet_dns_naptr_t *naptr = (const tnet_dns_naptr_t*)rr;
+ /* RFC 3403 - 6.2 E164 Example
+ Both the ENUM [18] and URI Resolution [4] Applications use the 'u'
+ flag. This flag states that the Rule is terminal and that the output
+ is a URI which contains the information needed to contact that
+ telephone service.
+ */
+ if (tsk_striequals(naptr->flags, "u") && tsk_striequals(naptr->services, service)){
+ /* RFC 3403 - 4.1 Packet Format
+ The fields (replacement and regexp) are also mutually exclusive. If a record is
+ returned that has values for both fields then it is considered to
+ be in error and SHOULD be either ignored or an error returned.
+ */
+ if (naptr->regexp && naptr->replacement){
+ continue;
+ }
+
+ if ((ret = tnet_dns_regex_parse(e164num, naptr->regexp))){
+ break;
+ }
+ }
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("We got an error response from the DNS server. Error code: %u", response->Header.RCODE);
+ }
+
+ TSK_OBJECT_SAFE_FREE(response);
+ }
+
+ return ret;
+}
+
+/**@ingroup tnet_dns_group
+* Performs DNS SRV resolution.
+* @param ctx The DNS context.
+* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create.
+* @param service The name of the service (e.g. SIP+D2U).
+* @param hostname The result containing an IP address or FQDN.
+* @param port The port associated to the result.
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref tnet_dns_resolve.
+*
+* @code
+* tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+* char* hostname = 0;
+* tnet_port_t port = 0;
+*
+* if(!tnet_dns_query_srv(ctx, "_sip._udp.sip2sip.info", &hostname, &port)){
+* TSK_DEBUG_INFO("DNS SRV succeed ==> hostname=%s and port=%u", hostname, port);
+* }
+*
+* TSK_FREE(hostname);
+* TSK_OBJECT_SAFE_FREE(ctx);
+* @endcode
+*/
+int tnet_dns_query_srv(tnet_dns_ctx_t *ctx, const char* service, char** hostname, tnet_port_t* port)
+{
+ tnet_dns_response_t *response;
+
+ if (!ctx){
+ return -1;
+ }
+
+ // tnet_dns_resolve is thread-safe
+ if ((response = tnet_dns_resolve(ctx, service, qclass_in, qtype_srv)))
+ {
+ const tsk_list_item_t *item;
+ const tnet_dns_rr_t* rr;
+ tsk_list_foreach(item, response->Answers) /* Already Filtered ==> Peek the first One */
+ {
+ rr = item->data;
+ if (rr->qtype == qtype_srv){
+ const tnet_dns_srv_t *srv = (const tnet_dns_srv_t*)rr;
+
+ tsk_strupdate(hostname, srv->target);
+ *port = srv->port;
+ break;
+ }
+ }
+ }
+
+ TSK_OBJECT_SAFE_FREE(response);
+
+ return (hostname && !tsk_strnullORempty(*hostname)) ? 0 : -2;
+}
+
+/**@ingroup tnet_dns_group
+* Performs DNS NAPTR followed by DNS SRV resolution.
+* @param ctx The DNS context.
+* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
+* @param domain The Name of the domain (e.g. google.com).
+* @param service The name of the service (e.g. SIP+D2U).
+* @param hostname The result containing an IP address or FQDN. Should be Null.
+* @param port The port associated to the result.
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref tnet_dns_resolve.
+*
+* @code
+* tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+* char* hostname = tsk_null;
+* tnet_port_t port = 0;
+*
+* if(!tnet_dns_query_naptr_srv(ctx, "sip2sip.info", "SIP+D2U", &hostname, &port)){
+* TSK_DEBUG_INFO("DNS NAPTR+SRV succeed ==> hostname=%s and port=%u", hostname, port);
+* }
+*
+* TSK_FREE(hostname);
+* TSK_OBJECT_SAFE_FREE(ctx);
+* @endcode
+*/
+int tnet_dns_query_naptr_srv(tnet_dns_ctx_t *ctx, const char* domain, const char* service, char** hostname, tnet_port_t* port)
+{
+ tnet_dns_response_t *response;
+
+ if (!ctx || !hostname){
+ TSK_DEBUG_ERROR("Invalid parameters.");
+ return -1;
+ }
+
+ /* reset (do not free the user supplied value). trying to free dummy value will cause access violation error ==> zero. */
+ *hostname = tsk_null;
+
+ // tnet_dns_resolve is thread-safe
+ if ((response = tnet_dns_resolve(ctx, domain, qclass_in, qtype_naptr))){
+ const tsk_list_item_t *item;
+ const tnet_dns_rr_t* rr;
+
+ char* replacement = tsk_null; /* e.g. _sip._udp.example.com */
+ char* flags = tsk_null;/* e.g. S, A, AAAA, A6, U, P ... */
+
+ tsk_list_foreach(item, response->Answers) /* Already Filtered ==> Peek the first One */
+ {
+ rr = item->data;
+ if (rr->qtype == qtype_naptr){
+ tnet_dns_naptr_t *naptr = (tnet_dns_naptr_t*)rr;
+
+ if (tsk_striequals(service, naptr->services)){
+ tsk_strupdate(&replacement, naptr->replacement);
+ tsk_strupdate(&flags, naptr->flags);
+
+ break;
+ }
+ }
+ }
+
+ if (flags && replacement){
+ if (tsk_striequals(flags, "S")){
+ tnet_dns_query_srv(ctx, replacement, hostname, port);
+ }
+ else if (tsk_striequals(flags, "A") || tsk_striequals(flags, "AAAA") || tsk_striequals(flags, "A6")){
+ TSK_DEBUG_WARN("Defaulting port value.");
+ tsk_strupdate(hostname, replacement);
+ *port = 5060;
+ }
+ else{
+ TSK_DEBUG_ERROR("DNS NAPTR query returned invalid flags");
+ }
+ }
+ else{
+ TSK_DEBUG_INFO("DNS NAPTR (%s) query returned zero result", domain);
+ }
+
+ TSK_FREE(flags);
+ TSK_FREE(replacement);
+ }
+
+ TSK_OBJECT_SAFE_FREE(response);
+
+ return (hostname && *hostname && !tsk_strempty(*hostname)) ? 0 : -2;
+}
+
+// remove timedout entries
+int tnet_dns_cache_maintenance(tnet_dns_ctx_t *ctx)
+{
+
+ if (ctx)
+ {
+ tsk_list_item_t *item;
+ tsk_safeobj_lock(ctx);
+ again:
+
+ tsk_list_foreach(item, ctx->cache)
+ {
+ // FIXME: ttl should be from RR::ttl
+ tnet_dns_cache_entry_t *entry = (tnet_dns_cache_entry_t*)item->data;
+ if ((entry->epoch + ctx->cache_ttl) < tsk_time_epoch()){
+ tsk_list_remove_item_by_data(ctx->cache, entry);
+ goto again; /* Do not delete data while looping */
+ }
+ }
+
+ tsk_safeobj_unlock(ctx);
+
+ return 0;
+ }
+ return -1;
+}
+
+// add an entry to the cache
+int tnet_dns_cache_entry_add(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t* response)
+{
+ int ret = -1;
+
+ if (ctx)
+ {
+ tnet_dns_cache_entry_t *entry;
+
+ tsk_safeobj_lock(ctx);
+
+ entry = 0;
+
+ /* Retrieve from cache */
+ entry = (tnet_dns_cache_entry_t*)tnet_dns_cache_entry_get(ctx, qname, qclass, qtype);
+
+ if (entry){
+ /* UPDATE */
+ TSK_OBJECT_SAFE_FREE(entry->response);
+ entry->response = tsk_object_ref(response);
+ entry->epoch = tsk_time_epoch();
+ ret = 0;
+ goto done;
+ }
+ else{
+ /* CREATE */
+ entry = tnet_dns_cache_entry_create(qname, qclass, qtype, response);
+ if (entry){
+ tsk_list_push_back_data(ctx->cache, (void**)&entry);
+ ret = 0;
+ goto done;
+ }
+ else{
+ ret = -2;
+ goto done;
+ }
+ }
+ done:
+ tsk_safeobj_unlock(ctx);
+ }
+ return ret;
+}
+
+// get an entry from the cache
+const tnet_dns_cache_entry_t* tnet_dns_cache_entry_get(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)
+{
+ tnet_dns_cache_entry_t *ret = tsk_null;
+ if (ctx)
+ {
+ tsk_list_item_t *item;
+
+ tsk_safeobj_lock(ctx);
+
+ tsk_list_foreach(item, ctx->cache){
+ tnet_dns_cache_entry_t *entry = (tnet_dns_cache_entry_t*)item->data;
+ if (entry->qtype == qtype && entry->qclass == qclass && tsk_strequals(entry->qname, qname)){
+ ret = entry;
+ break;
+ }
+ }
+
+ tsk_safeobj_unlock(ctx);
+ }
+
+ return ret;
+}
+
+
+/**@ingroup tnet_dns_group
+* Adds new DNS server to the list of the list of servers to query.
+* @param ctx DNS context containing the user parameters. The new DNS server will be added to this context.
+* @param host The IP address (or FQDN) of the dns server to add to the server.
+* @retval zero if succeed and non-zero error code otherwise.
+*/
+int tnet_dns_add_server(tnet_dns_ctx_t *ctx, const char* host)
+{
+ tnet_address_t *address;
+
+ if (!ctx || !host){
+ return -1;
+ }
+
+ if (!ctx->servers){
+ ctx->servers = tsk_list_create();
+ }
+
+ if ((address = tnet_address_create(host))){
+ address->family = tnet_get_family(host, TNET_DNS_SERVER_PORT_DEFAULT);
+ address->dnsserver = 1;
+ tsk_list_push_ascending_data(ctx->servers, (void**)&address);
+
+ return 0;
+ }
+
+ return -2;
+}
+
+//=================================================================================================
+// [[DNS CACHE ENTRY]] object definition
+//
+static tsk_object_t* tnet_dns_cache_entry_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_cache_entry_t *entry = self;
+ if (entry){
+ entry->qname = tsk_strdup(va_arg(*app, const char*));
+ entry->qclass = va_arg(*app, tnet_dns_qclass_t);
+ entry->qtype = va_arg(*app, tnet_dns_qtype_t);
+ entry->response = tsk_object_ref(va_arg(*app, tnet_dns_response_t*));
+
+ entry->epoch = tsk_time_epoch();
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_cache_entry_dtor(tsk_object_t * self)
+{
+ tnet_dns_cache_entry_t *entry = self;
+ if (entry){
+ TSK_OBJECT_SAFE_FREE(entry->response);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_cache_entry_def_s =
+{
+ sizeof(tnet_dns_cache_entry_t),
+ tnet_dns_cache_entry_ctor,
+ tnet_dns_cache_entry_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_cache_entry_def_t = &tnet_dns_cache_entry_def_s;
+
+
+//=================================================================================================
+// [[DNS CONTEXT]] object definition
+//
+static tsk_object_t* tnet_dns_ctx_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_ctx_t *ctx = self;
+ if (ctx){
+ ctx->timeout = TNET_DNS_TIMEOUT_DEFAULT;
+ ctx->recursion = tsk_true;
+ ctx->edns0 = tsk_true;
+ ctx->caching = tsk_false;
+
+ ctx->cache_ttl = TNET_DNS_CACHE_TTL;
+
+ ctx->server_port = TNET_DNS_SERVER_PORT_DEFAULT;
+
+ /* Gets all dns servers. */
+ ctx->servers = tnet_get_addresses_all_dnsservers();
+ /* Creates empty cache. */
+ ctx->cache = tsk_list_create();
+
+#if HAVE_DNS_H
+ ctx->resolv_handle = dns_open(NULL);
+#endif
+
+ tsk_safeobj_init(ctx);
+ }
+ return self;
+ }
+
+static tsk_object_t* tnet_dns_ctx_dtor(tsk_object_t * self)
+{
+ tnet_dns_ctx_t *ctx = self;
+ if (ctx){
+ tsk_safeobj_deinit(ctx);
+
+ TSK_OBJECT_SAFE_FREE(ctx->servers);
+ TSK_OBJECT_SAFE_FREE(ctx->cache);
+
+#if HAVE_DNS_H
+ dns_free(ctx->resolv_handle);
+#endif
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_ctx_def_s =
+{
+ sizeof(tnet_dns_ctx_t),
+ tnet_dns_ctx_ctor,
+ tnet_dns_ctx_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_ctx_def_t = &tnet_dns_ctx_def_s;
diff --git a/tinyNET/src/dns/tnet_dns.h b/tinyNET/src/dns/tnet_dns.h
new file mode 100644
index 0000000..d4c2e6d
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns.h
@@ -0,0 +1,125 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns.h
+ * @brief DNS utilities functions (RFCS [1034 1035] [2671] [3401 3402 3403 3404] [3761]).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef TNET_DNS_H
+#define TNET_DNS_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_message.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_safeobj.h"
+
+#if HAVE_DNS_H
+#include <dns.h>
+#endif
+
+TNET_BEGIN_DECLS
+
+/**@ingroup tnet_dns_group
+*/
+#define TNET_DNS_CACHE_TTL (15000 * 1000)
+
+/**@ingroup tnet_dns_group
+* Default timeout (in milliseconds) value for DNS queries.
+*/
+#define TNET_DNS_TIMEOUT_DEFAULT 5000 //(5 seconds)
+
+/**@ingroup tnet_dns_group
+* Maximum supported Dgram size to advertise using EDNS0.
+*/
+#define TNET_DNS_DGRAM_SIZE_DEFAULT 4096
+
+/**@ingroup tnet_dns_group
+*/
+#define TNET_DNS_SERVER_PORT_DEFAULT 53
+
+/**DNS cache entry.
+*/
+typedef struct tnet_dns_cache_entry_s
+{
+ TSK_DECLARE_OBJECT;
+
+ char* qname;
+ tnet_dns_qclass_t qclass;
+ tnet_dns_qtype_t qtype;
+
+ uint64_t epoch;
+
+ tnet_dns_response_t *response;
+}
+tnet_dns_cache_entry_t;
+typedef tsk_list_t tnet_dns_cache_entries_L_t;
+typedef tnet_dns_cache_entries_L_t tnet_dns_cache_t;
+
+/**DNS context.
+*/
+typedef struct tnet_dns_ctx_s
+{
+ TSK_DECLARE_OBJECT;
+
+ uint64_t timeout; /**< In milliseconds. Default: @ref TNET_DNS_TIMEOUT_DEFAULT. */
+ tsk_bool_t recursion; /**< Indicates whether to direct the name server to pursue the query recursively. Default: enabled.*/
+ tsk_bool_t edns0; /**< Indicates whether to enable EDNS0 (Extension Mechanisms for DNS) or not. This option will allow you to send DNS packet larger than 512 bytes. Default: enabled. */
+ tsk_bool_t caching; /**< Indicates whether to enable the DNS cache or not. Default: no. */
+
+ int32_t cache_ttl;
+
+ tnet_port_t server_port; /**< Default port (@a TNET_DNS_SERVER_PORT_DEFAULT)) */
+
+ tnet_dns_cache_t *cache;
+ tnet_addresses_L_t *servers;
+
+ TSK_DECLARE_SAFEOBJ;
+
+#if HAVE_DNS_H
+ dns_handle_t resolv_handle;
+#endif
+}
+tnet_dns_ctx_t;
+
+TINYNET_API int tnet_dns_cache_clear(tnet_dns_ctx_t* ctx);
+TINYNET_API tnet_dns_response_t* tnet_dns_resolve(tnet_dns_ctx_t* ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype);
+TINYNET_API tnet_dns_response_t* tnet_dns_enum(tnet_dns_ctx_t* ctx, const char* e164num, const char* domain);
+TINYNET_API char* tnet_dns_enum_2(tnet_dns_ctx_t* ctx, const char* service, const char* e164num, const char* domain);
+TINYNET_API int tnet_dns_query_srv(tnet_dns_ctx_t *ctx, const char* service, char** hostname, tnet_port_t* port);
+TINYNET_API int tnet_dns_query_naptr_srv(tnet_dns_ctx_t *ctx, const char* domain, const char* service, char** hostname, tnet_port_t* port);
+
+TINYNET_API int tnet_dns_add_server(tnet_dns_ctx_t *ctx, const char* host);
+
+TINYNET_API tnet_dns_ctx_t* tnet_dns_ctx_create();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ctx_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_cache_entry_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_H */
diff --git a/tinyNET/src/dns/tnet_dns_a.c b/tinyNET/src/dns/tnet_dns_a.c
new file mode 100644
index 0000000..27a3603
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_a.c
@@ -0,0 +1,102 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_a.c
+ * @brief DNS Address record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_a.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+/** Creates new DNS A Resource Record.
+*/
+tnet_dns_a_t* tnet_dns_a_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_a_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+
+//=================================================================================================
+// [[DNS A]] object definition
+//
+static tsk_object_t* tnet_dns_a_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_a_t *a = self;
+ if(a){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+ uint16_t rdlength = tsk_va_arg_u16(*app);
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ const uint8_t* rddata = (((uint8_t*)data) + offset);
+ //const uint8_t* dataEnd = (rddata + rdlength);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(a), qtype_a, qclass);
+ TNET_DNS_RR(a)->name = tsk_strdup(name);
+ TNET_DNS_RR(a)->rdlength = rdlength;
+ TNET_DNS_RR(a)->ttl = ttl;
+
+ if(rddata && rdlength && (rdlength == 4/* 32bits */)){
+ // ==> DESERIALIZATION
+ /* ADDRESS */
+ uint32_t address = (uint32_t)tnet_htonl_2(rddata);
+ tsk_sprintf(&(a->address), "%u.%u.%u.%u", (address>>24)&0xFF, (address>>16)&0xFF, (address>>8)&0xFF, (address>>0)&0xFF);
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid IPv4 address.");
+ }
+
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_a_dtor(tsk_object_t * self)
+{
+ tnet_dns_a_t *a = self;
+ if(a){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(a));
+
+ TSK_FREE(a->address);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_a_def_s =
+{
+ sizeof(tnet_dns_a_t),
+ tnet_dns_a_ctor,
+ tnet_dns_a_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_a_def_t = &tnet_dns_a_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_a.h b/tinyNET/src/dns/tnet_dns_a.h
new file mode 100644
index 0000000..e5db962
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_a.h
@@ -0,0 +1,61 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_a.h
+ * @brief DNS Address record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_A_H
+#define TNET_DNS_RR_A_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+TNET_BEGIN_DECLS
+
+
+/**DNS A Resource Record.
+*/
+typedef struct tnet_dns_a_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.4.1. A RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* address;
+}
+tnet_dns_a_t;
+
+TINYNET_API tnet_dns_a_t* tnet_dns_a_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_a_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_A_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_aaaa.c b/tinyNET/src/dns/tnet_dns_aaaa.c
new file mode 100644
index 0000000..4855827
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_aaaa.c
@@ -0,0 +1,104 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_aaaA.c
+ * @brief DNS IPv6 address record - RR - (RFC 3596).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_aaaa.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+/** Creates new DNS AAAA Resource Record.
+*/
+
+tnet_dns_aaaa_t* tnet_dns_aaaa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_aaaa_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+
+//=================================================================================================
+// [[DNS AAAA]] object definition
+//
+static tsk_object_t* tnet_dns_aaaa_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_aaaa_t *aaaa = self;
+ if(aaaa){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+ uint16_t rdlength = tsk_va_arg_u16(*app);
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ const uint8_t* rddata = (((uint8_t*)data) + offset);
+ //const uint8_t* dataEnd = (rddata + rdlength);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(aaaa), qtype_aaaa, qclass);
+ TNET_DNS_RR(aaaa)->name = tsk_strdup(name);
+ TNET_DNS_RR(aaaa)->rdlength = rdlength;
+ TNET_DNS_RR(aaaa)->ttl = ttl;
+
+ if(rddata && rdlength && (rdlength == 16/* 128bits */)){
+ // ==> DESERIALIZATION
+ /* ADDRESS */
+ tsk_sprintf(&(aaaa->address), "%x:%x:%x:%x:%x:%x:%x:%x",
+ tnet_ntohs_2(&rddata[0]), tnet_ntohs_2(&rddata[2]), tnet_ntohs_2(&rddata[4]), tnet_ntohs_2(&rddata[6]),
+ tnet_ntohs_2(&rddata[8]), tnet_ntohs_2(&rddata[10]), tnet_ntohs_2(&rddata[12]), tnet_ntohs_2(&rddata[14]));
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid IPv6 address.");
+ }
+
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_aaaa_dtor(tsk_object_t * self)
+{
+ tnet_dns_aaaa_t *aaaa = self;
+ if(aaaa){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(aaaa));
+
+ TSK_FREE(aaaa->address);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_aaaa_def_s =
+{
+ sizeof(tnet_dns_aaaa_t),
+ tnet_dns_aaaa_ctor,
+ tnet_dns_aaaa_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_aaaa_def_t = &tnet_dns_aaaa_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_aaaa.h b/tinyNET/src/dns/tnet_dns_aaaa.h
new file mode 100644
index 0000000..759adf1
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_aaaa.h
@@ -0,0 +1,58 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_aaaa.h
+ * @brief DNS IPv6 address record - RR - (RFC 3596).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_AAAA_H
+#define TNET_DNS_RR_AAAA_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+/**DNS AAAA Resource Record.
+*/
+typedef struct tnet_dns_aaaa_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 3596 -
+ */
+ char* address;
+}
+tnet_dns_aaaa_t;
+
+tnet_dns_aaaa_t* tnet_dns_aaaa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_aaaa_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_AAAA_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_cname.c b/tinyNET/src/dns/tnet_dns_cname.c
new file mode 100644
index 0000000..8bec3e8
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_cname.c
@@ -0,0 +1,93 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_cname.c
+ * @brief DNS Mail eXchange record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_cname.h"
+
+#include "../tnet_types.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+/** Creates new DNS CNAME Resource Record.
+*/
+
+tnet_dns_cname_t* tnet_dns_cname_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_cname_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+
+//=================================================================================================
+// [[DNS CNAME]] object definition
+//
+static tsk_object_t* tnet_dns_cname_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_cname_t *cname = self;
+ if(cname){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+ uint16_t rdlength = tsk_va_arg_u16(*app);
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(cname), qtype_cname, qclass);
+ TNET_DNS_RR(cname)->name = tsk_strdup(name);
+ TNET_DNS_RR(cname)->rdlength = rdlength;
+ TNET_DNS_RR(cname)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* CNAME */
+ tnet_dns_rr_qname_deserialize(data, &(cname->cname), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_cname_dtor(tsk_object_t * self)
+{
+ tnet_dns_cname_t *cname = self;
+ if(cname){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(cname));
+
+ TSK_FREE(cname->cname);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_cname_def_s =
+{
+ sizeof(tnet_dns_cname_t),
+ tnet_dns_cname_ctor,
+ tnet_dns_cname_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_cname_def_t = &tnet_dns_cname_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_cname.h b/tinyNET/src/dns/tnet_dns_cname.h
new file mode 100644
index 0000000..f97087d
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_cname.h
@@ -0,0 +1,63 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_cname.h
+ * @brief DNS Mail eXchange record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_CNAME_H
+#define TNET_DNS_RR_CNAME_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+
+/** DNS CNAME Resource Record
+*/
+typedef struct tnet_dns_cname_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* 3.3.1. CNAME RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* cname;
+}
+tnet_dns_cname_t;
+
+tnet_dns_cname_t* tnet_dns_cname_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_cname_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_CNAME_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_message.c b/tinyNET/src/dns/tnet_dns_message.c
new file mode 100644
index 0000000..594f499
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_message.c
@@ -0,0 +1,359 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_message.h
+ * @brief DNS Message holding RRs (RFC 1035).
+ *
+ */
+#include "tnet_dns_message.h"
+
+#include "../tnet_utils.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+/**@ingroup tnet_dns_group
+* Creates new DNS message.
+* @sa tnet_dns_message_create_null.
+*/
+tnet_dns_message_t* tnet_dns_message_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tsk_bool_t isquery)
+{
+ return tsk_object_new(tnet_dns_message_def_t, qname, qclass, qtype, isquery);
+}
+
+/**@ingroup tnet_dns_group
+* Creates new DNS message.
+* @sa tnet_dns_message_create.
+*/
+tnet_dns_message_t* tnet_dns_message_create_null()
+{
+ return tnet_dns_message_create(tsk_null, qclass_any, qtype_any, tsk_false);
+}
+
+/**@ingroup tnet_dns_group
+* Creates new DNS response message.
+* @sa tnet_dns_query_create.
+*/
+tnet_dns_response_t* tnet_dns_response_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)
+{
+ return tnet_dns_message_create(qname, qclass, qtype, tsk_false);
+}
+
+/**@ingroup tnet_dns_group
+* Creates new DNS query message.
+* @sa tnet_dns_response_create.
+*/
+tnet_dns_query_t* tnet_dns_query_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)
+{
+ return tnet_dns_message_create(qname, qclass, qtype, tsk_true);
+}
+
+/**@ingroup tnet_dns_group
+* Serializes a DNS message in binary data.
+* @param message The DNS message to seriablize.
+* @retval The binary buffer containong the message if succeed. Otherwise, @a tsk_null is returned.
+* @sa tnet_dns_message_deserialize.
+*/
+tsk_buffer_t* tnet_dns_message_serialize(const tnet_dns_message_t *message)
+{
+ tsk_buffer_t* output = tsk_null;
+ uint16_t _2bytes;
+ tsk_list_item_t *item;
+
+ /* Check message validity */
+ if (!message){
+ goto bail;
+ }
+
+ /* Creates empty buffer */
+ output = tsk_buffer_create_null();
+
+ /* ==============================
+ * HEADER
+ */
+ //tsk_buffer_append(output, &(message->Header), sizeof(message->Header));
+
+ /* ID */
+ _2bytes = tnet_ntohs(message->Header.ID);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* |QR| Opcode |AA|TC|RD|RA| Z | RCODE | */
+ {
+ uint16_t temp, _2bytes = 0;
+
+ temp = message->Header.QR, temp <<= 15;
+ _2bytes |= temp;
+
+ temp = message->Header.OPCODE, temp <<= 11;
+ _2bytes |= temp;
+
+ temp = message->Header.AA, temp <<= 10;
+ _2bytes |= temp;
+
+ temp = message->Header.TC, temp <<= 9;
+ _2bytes |= temp;
+
+ temp = message->Header.RD, temp <<= 8;
+ _2bytes |= temp;
+
+ temp = message->Header.RA, temp <<= 7;
+ _2bytes |= temp;
+
+ temp = message->Header.Z, temp <<= 4;
+ _2bytes |= temp;
+
+ temp = message->Header.RCODE, temp <<= 4;
+ _2bytes |= temp;
+
+ _2bytes = tnet_ntohs(_2bytes);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ }
+ /* QDCOUNT */
+ _2bytes = tnet_ntohs(message->Header.QDCOUNT);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* ANCOUNT */
+ _2bytes = tnet_ntohs(message->Header.ANCOUNT);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* NSCOUNT */
+ _2bytes = tnet_ntohs(message->Header.NSCOUNT);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* ARCOUNT */
+ _2bytes = tnet_ntohs(message->Header.ARCOUNT);
+ tsk_buffer_append(output, &(_2bytes), 2);
+
+
+ /* ==============================
+ * QUESTION
+ */
+ if (TNET_DNS_MESSAGE_IS_QUERY(message))
+ {
+ /* QNAME */
+ tnet_dns_rr_qname_serialize(message->Question.QNAME, output);
+ /* QTYPE */
+ _2bytes = tnet_ntohs(message->Question.QTYPE);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* QCLASS */
+ _2bytes = tnet_ntohs(message->Question.QCLASS);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ }
+
+ /* ==============================
+ * ANSWERS
+ */
+ tsk_list_foreach(item, message->Answers)
+ {
+ tnet_dns_rr_serialize((tnet_dns_rr_t *)item->data, output);
+ }
+
+ /* ==============================
+ * AUTHORITIES
+ */
+ tsk_list_foreach(item, message->Authorities)
+ {
+ tnet_dns_rr_serialize((tnet_dns_rr_t *)item->data, output);
+ }
+
+ /* ==============================
+ * ADDITIONALS
+ */
+ tsk_list_foreach(item, message->Additionals)
+ {
+ tnet_dns_rr_serialize((tnet_dns_rr_t *)item->data, output);
+ }
+
+
+bail:
+ return output;
+}
+
+/**@ingroup tnet_dns_group
+* Deserialize a STUN message from binary data.
+* @param data A pointer to the binary data.
+* @param size The size of the bnary data buffer.
+* @retval @ref tnet_dns_message_t object if succeed or NULL otherwise.
+* @sa @ref tnet_dns_message_serialize.
+*/
+tnet_dns_message_t* tnet_dns_message_deserialize(const uint8_t *data, tsk_size_t size)
+{
+ tnet_dns_message_t *message = 0;
+ uint8_t *dataPtr, *dataEnd, *dataStart;
+ uint16_t i;
+ tsk_size_t offset = 0;
+
+ if (!data || !size){
+ goto bail;
+ }
+
+ dataPtr = (uint8_t*)data;
+ dataStart = dataPtr;
+ dataEnd = (dataStart + size);
+
+ message = tnet_dns_message_create_null();
+
+ /* === HEADER ===*/
+ /* ID */
+ message->Header.ID = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /* |QR| Opcode |AA|TC|RD|RA| Z | RCODE | */
+ {
+ uint16_t flags = tnet_ntohs_2(dataPtr);
+
+ message->Header.QR = (flags >> 15);
+ message->Header.OPCODE = ((flags >> 11) & 0x000F);
+ message->Header.AA = ((flags >> 10) & 0x0001);
+ message->Header.TC = ((flags >> 9) & 0x0001);
+ message->Header.RD = ((flags >> 8) & 0x0001);
+ message->Header.RA = ((flags >> 7) & 0x0001);
+ message->Header.Z = ((flags >> 4) & 0x0007);
+ message->Header.RCODE = (flags & 0x000F);
+
+ dataPtr += 2;
+ }
+ /* QDCOUNT */
+ message->Header.QDCOUNT = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /* ANCOUNT */
+ message->Header.ANCOUNT = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /* NSCOUNT */
+ message->Header.NSCOUNT = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /* ARCOUNT */
+ message->Header.ARCOUNT = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+
+ /* === Queries ===*/
+ offset = (tsk_size_t)(dataPtr - dataStart);
+ for (i = 0; i < message->Header.QDCOUNT; i++)
+ {
+ /* Do not need to parse queries in the response ==> silently ignore */
+ char* name = 0;
+ tnet_dns_rr_qname_deserialize(dataStart, &name, &offset); /* QNAME */
+ dataPtr += offset;
+ dataPtr += 4, offset += 4; /* QTYPE + QCLASS */
+ TSK_FREE(name);
+ }
+ dataPtr = (dataStart + offset); /* TODO: remove ==> obly for debug tests */
+
+ /* === Answers ===*/
+ offset = (tsk_size_t)(dataPtr - dataStart);
+ for (i = 0; i < message->Header.ANCOUNT; i++)
+ {
+ tnet_dns_rr_t* rr = tnet_dns_rr_deserialize(dataStart, (tsk_size_t)(dataEnd - dataPtr), &offset);
+ if (rr){
+ if (!message->Answers){
+ message->Answers = tsk_list_create();
+ }
+ /* Push in descending order (useful for NAPTR and SRV records). */
+ tsk_list_push_descending_data(message->Answers, (void**)&rr);
+ }
+ }
+ dataPtr = (dataStart + offset);
+
+ /* === Authorities ===*/
+ offset = (tsk_size_t)(dataPtr - dataStart);
+ for (i = 0; i < message->Header.NSCOUNT; i++)
+ {
+ tnet_dns_rr_t* rr = tnet_dns_rr_deserialize(dataStart, (tsk_size_t)(dataEnd - dataPtr), &offset);
+ if (rr){
+ if (!message->Authorities){
+ message->Authorities = tsk_list_create();
+ }
+ tsk_list_push_back_data(message->Authorities, (void**)&rr);
+ }
+ }
+ dataPtr = (dataStart + offset);
+
+ /* === Additionals ===*/
+ offset = (tsk_size_t)(dataPtr - dataStart);
+ for (i = 0; i < message->Header.ARCOUNT; i++)
+ {
+ tnet_dns_rr_t* rr = tnet_dns_rr_deserialize(dataStart, (tsk_size_t)(dataEnd - dataPtr), &offset);
+ if (rr){
+ if (!message->Additionals){
+ message->Additionals = tsk_list_create();
+ }
+ tsk_list_push_back_data(message->Additionals, (void**)&rr);
+ }
+ }
+ dataPtr = (dataStart + offset);
+
+
+bail:
+ return message;
+}
+
+//=================================================================================================
+// [[DNS MESSAGE]] object definition
+//
+static tsk_object_t* tnet_dns_message_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_message_t *message = self;
+ if (message){
+ static uint16_t __dnsmessage_unique_id = 0;
+
+ const char* qname = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ tnet_dns_qtype_t qtype = va_arg(*app, tnet_dns_qtype_t);
+ tsk_bool_t isquery = va_arg(*app, tsk_bool_t);
+
+ /* Create random ID. */
+ message->Header.ID = ++__dnsmessage_unique_id;
+
+ /* QR field ==> query (0) - response (1) */
+ message->Header.QR = isquery ? 0 : 1;
+
+ if (isquery){
+ /* QDCOUNT field ==> at least one question */
+ message->Header.QDCOUNT = 1;
+ }
+
+ if (qname){
+ message->Question.QNAME = tsk_strdup(qname);
+ message->Question.QTYPE = qtype;
+ message->Question.QCLASS = qclass;
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_message_dtor(tsk_object_t * self)
+{
+ tnet_dns_message_t *message = self;
+ if (message){
+ TSK_FREE(message->Question.QNAME);
+
+ TSK_OBJECT_SAFE_FREE(message->Answers);
+ TSK_OBJECT_SAFE_FREE(message->Authorities);
+ TSK_OBJECT_SAFE_FREE(message->Additionals);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_message_def_s =
+{
+ sizeof(tnet_dns_message_t),
+ tnet_dns_message_ctor,
+ tnet_dns_message_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_message_def_t = &tnet_dns_message_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_message.h b/tinyNET/src/dns/tnet_dns_message.h
new file mode 100644
index 0000000..8506ff8
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_message.h
@@ -0,0 +1,209 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_message.h
+ * @brief DNS Message holding RRs (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef TNET_DNS_MESSAGE_H
+#define TNET_DNS_MESSAGE_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+#include "tsk_buffer.h"
+
+/**@ingroup tnet_dns_group
+* @def TNET_DNS_MESSAGE_IS_RESPONSE
+* Checks whether the STUN message is a response or not(query).
+* @sa TNET_DNS_MESSAGE_IS_QUERY.
+*/
+/**@ingroup tnet_dns_group
+* @def TNET_DNS_MESSAGE_IS_QUERY
+* Checks whether the STUN message is a query or not(response).
+* @sa TNET_DNS_MESSAGE_IS_RESPONSE.
+*/
+
+TNET_BEGIN_DECLS
+
+
+#define TNET_DNS_MESSAGE_IS_RESPONSE(message) ((message) && (message)->Header.QR == 1)
+#define TNET_DNS_MESSAGE_IS_QUERY(message) ((message) && (message)->Header.QR == 0)
+
+/**@ingroup tnet_dns_group
+* @def TNET_DNS_RESPONSE_IS_SUCCESS
+* Checks whether the STUN message is a success response or not(error).
+* @sa TNET_DNS_RESPONSE_IS_ERROR.
+*/
+/**@ingroup tnet_dns_group
+* @def TNET_DNS_RESPONSE_IS_ERROR
+* Checks whether the STUN message is an error response or not(success).
+* @sa TNET_DNS_RESPONSE_IS_SUCCESS.
+*/
+#define TNET_DNS_RESPONSE_IS_SUCCESS(response) ((response) && (response)->Header.RCODE == rcode_noerror)
+#define TNET_DNS_RESPONSE_IS_ERROR(response) !TNET_DNS_RESPONSE_IS_SUCCESS(response)
+
+/**Response codes as per RFC 1035 subclause 4.1.1.
+*/
+typedef enum tnet_dns_rcode_e
+{
+ rcode_noerror = 0,
+ rcode_error_format = 1,
+ rcode_server_failure = 2,
+ rcode_error_name = 3,
+ rcode_notimplemented = 4,
+ rcode_refused = 5
+}
+tnet_dns_rcode_t;
+
+/**OPCODE defining the kind of query as per RFC 1035 subclause 4.1.1.
+*/
+typedef enum tnet_dns_opcode_e
+{
+ opcode_query = 0, /**< 0 a standard query (QUERY) */
+ opcode_iquery = 1, /**< 1 an inverse query (IQUERY) */
+ opcode_status = 2, /**< 2 a server status request (STATUS) */
+}
+tnet_dns_opcode_t;
+
+/** DNS message as per RFC 1035 subclause 4.
+*/
+typedef struct tnet_dns_message_s
+{
+ TSK_DECLARE_OBJECT;
+
+ /* RFC 1035 - 4.1. Format
+ +---------------------+
+ | Header |
+ +---------------------+
+ | Question | the question for the name server
+ +---------------------+
+ | Answer | RRs answering the question
+ +---------------------+
+ | Authority | RRs pointing toward an authority
+ +---------------------+
+ | Additional | RRs holding additional information
+ +---------------------+
+ */
+
+ /* RFC 1035 - 4.1.1. Header section format
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ID |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QDCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ANCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | NSCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ARCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ struct
+ {
+ uint16_t ID;
+ unsigned QR:1;
+ unsigned OPCODE:4; /* see @ref tnet_dns_opcode_t */
+ unsigned AA:1;
+ unsigned TC:1;
+ unsigned RD:1;
+ unsigned RA:1;
+ unsigned Z:3;
+ unsigned RCODE:4; /* see @ref tnet_dns_rcode_t */
+ uint16_t QDCOUNT;
+ uint16_t ANCOUNT;
+ uint16_t NSCOUNT;
+ uint16_t ARCOUNT;
+ }
+ Header;
+
+ /* RFc 1035 - 4.1.2. Question section format
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / QNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QTYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QCLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ struct
+ {
+ /** RFC 1035 - 4.1.2. Question section format
+ a domain name represented as a sequence of labels, where
+ each label consists of a length octet followed by that
+ number of octets. The domain name terminates with the
+ zero length octet for the null label of the root. Note
+ that this field may be an odd number of octets; no
+ padding is used.*/
+ void* QNAME;
+ /** RFC 1035 - 4.1.2. Question section format
+ a two octet code which specifies the type of the query.
+ The values for this field include all codes valid for a
+ TYPE field, together with some more general codes which
+ can match more than one type of RR.*/
+ tnet_dns_qtype_t QTYPE;
+ /* RFC 1035 - 4.1.2. Question section format
+ a two octet code that specifies the class of the query.
+ For example, the QCLASS field is IN for the Internet.
+ */
+ tnet_dns_qclass_t QCLASS;
+ }
+ Question;
+
+ tnet_dns_rrs_L_t *Answers; /**< Filtered answers by priority. */
+ tnet_dns_rrs_L_t *Authorities;
+ tnet_dns_rrs_L_t *Additionals;
+}
+tnet_dns_message_t;
+
+typedef tsk_list_t tnet_dns_messages_L_t; /**< List of @ref tnet_dns_message_t elements. */
+typedef tnet_dns_message_t tnet_dns_query_t; /**< DNS Query messsage. */
+typedef tnet_dns_message_t tnet_dns_response_t; /**< DNS response message. */
+
+tsk_buffer_t* tnet_dns_message_serialize(const tnet_dns_message_t *message);
+tnet_dns_message_t* tnet_dns_message_deserialize(const uint8_t *data, tsk_size_t size);
+
+
+tnet_dns_message_t* tnet_dns_message_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tsk_bool_t isquery);
+tnet_dns_message_t* tnet_dns_message_create_null();
+tnet_dns_response_t* tnet_dns_response_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype);
+tnet_dns_query_t* tnet_dns_query_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_message_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_MESSAGE_H */
+
+
diff --git a/tinyNET/src/dns/tnet_dns_mx.c b/tinyNET/src/dns/tnet_dns_mx.c
new file mode 100644
index 0000000..edc59b1
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_mx.c
@@ -0,0 +1,95 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_mx.c
+ * @brief DNS Mail eXchange record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_mx.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+/** Creates new DNS MX Resource Record.
+*/
+tnet_dns_mx_t* tnet_dns_mx_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_mx_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS MX]] object definition
+//
+static tsk_object_t* tnet_dns_mx_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_mx_t *mx = self;
+ if(mx){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+ uint16_t rdlength = tsk_va_arg_u16(*app);
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(mx), qtype_mx, qclass);
+ TNET_DNS_RR(mx)->name = tsk_strdup(name);
+ TNET_DNS_RR(mx)->rdlength = rdlength;
+ TNET_DNS_RR(mx)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* PREFERENCE */
+ mx->preference = tnet_ntohs_2(((uint8_t*)data) + offset);
+ offset += 2;
+ /* EXCHANGE */
+ tnet_dns_rr_qname_deserialize(data, &(mx->exchange), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_mx_dtor(tsk_object_t * self)
+{
+ tnet_dns_mx_t *mx = self;
+ if(mx){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(mx));
+
+ TSK_FREE(mx->exchange);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_mx_def_s =
+{
+ sizeof(tnet_dns_mx_t),
+ tnet_dns_mx_ctor,
+ tnet_dns_mx_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_mx_def_t = &tnet_dns_mx_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_mx.h b/tinyNET/src/dns/tnet_dns_mx.h
new file mode 100644
index 0000000..98a00f1
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_mx.h
@@ -0,0 +1,66 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_mx.h
+ * @brief DNS Mail eXchange record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_MX_H
+#define TNET_DNS_RR_MX_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+
+/** DNS MX Resource Record
+*/
+typedef struct tnet_dns_mx_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.3.9. MX RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PREFERENCE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EXCHANGE /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ uint16_t preference;
+ char* exchange;
+}
+tnet_dns_mx_t;
+
+tnet_dns_mx_t* tnet_dns_mx_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_mx_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_MX_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_naptr.c b/tinyNET/src/dns/tnet_dns_naptr.c
new file mode 100644
index 0000000..79d7f70
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_naptr.c
@@ -0,0 +1,142 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_naptr.c
+ * @brief DNS Naming Authority Pointer - RR - (RFC 3403).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_naptr.h"
+
+
+#include "../tnet_types.h"
+#include "./tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+
+/** Creates new DNS NAPTR Resource Record.
+*/
+tnet_dns_naptr_t* tnet_dns_naptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_naptr_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+
+
+//=================================================================================================
+// [[DNS NAPTR]] object definition
+//
+static tsk_object_t* tnet_dns_naptr_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_naptr_t *naptr = self;
+ if(naptr){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+ uint16_t rdlength = tsk_va_arg_u16(*app);
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(naptr), qtype_naptr, qclass);
+ TNET_DNS_RR(naptr)->name = tsk_strdup(name);
+ TNET_DNS_RR(naptr)->rdlength = rdlength;
+ TNET_DNS_RR(naptr)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* ORDER */
+ naptr->order = tnet_ntohs_2(((uint8_t*)data) + offset);
+ offset += 2;
+ /* PREFERENCE */
+ naptr->preference = tnet_ntohs_2(((uint8_t*)data) + offset);
+ offset += 2;
+ /* FLAGS */
+ tnet_dns_rr_charstring_deserialize(data, &(naptr->flags), &offset);
+ /* SERVICES */
+ tnet_dns_rr_charstring_deserialize(data, &(naptr->services), &offset);
+ /* REGEXP */
+ tnet_dns_rr_charstring_deserialize(data, &(naptr->regexp), &offset);
+ /* REPLACEMENT */
+ tnet_dns_rr_qname_deserialize(data, &(naptr->replacement), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_naptr_dtor(tsk_object_t * self)
+{
+ tnet_dns_naptr_t *naptr = self;
+ if(naptr){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(naptr));
+
+ TSK_FREE(naptr->flags);
+ TSK_FREE(naptr->services);
+ TSK_FREE(naptr->regexp);
+ TSK_FREE(naptr->replacement);
+ }
+ return self;
+}
+
+static int tnet_dns_naptr_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
+{
+ const tnet_dns_rr_t* rr1 = obj1;
+ const tnet_dns_rr_t* rr2 = obj2;
+
+ if(rr1 && rr2 && (rr1->qtype==qtype_naptr) && (rr2->qtype==qtype_naptr)){
+ const tnet_dns_naptr_t* naptr1 = (tnet_dns_naptr_t*)rr1;
+ const tnet_dns_naptr_t* naptr2 = (tnet_dns_naptr_t*)rr2;
+
+ /* Compare orders. */
+ if(naptr1->order < naptr2->order){ /* Lowest order is tried first. */
+ return 1;
+ }
+ else if(naptr1->order > naptr2->order){
+ return -1;
+ }
+
+ /* Compare preference */
+ if(naptr1->order < naptr2->order){ /* Lowest preference is tried first. */
+ return 1;
+ }
+ else if(naptr1->order > naptr2->order){
+ return -1;
+ }
+
+ return 0;
+ }
+ else{
+ return -1;
+ }
+}
+
+static const tsk_object_def_t tnet_dns_naptr_def_s =
+{
+ sizeof(tnet_dns_naptr_t),
+ tnet_dns_naptr_ctor,
+ tnet_dns_naptr_dtor,
+ tnet_dns_naptr_cmp,
+};
+const tsk_object_def_t *tnet_dns_naptr_def_t = &tnet_dns_naptr_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_naptr.h b/tinyNET/src/dns/tnet_dns_naptr.h
new file mode 100644
index 0000000..b960809
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_naptr.h
@@ -0,0 +1,81 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_naptr.h
+ * @brief DNS Naming Authority Pointer - RR - (RFC 3403).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_NAPTR_H
+#define TNET_DNS_RR_NAPTR_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+TNET_BEGIN_DECLS
+
+/** DNS NAPTR Resource Record
+*/
+typedef struct tnet_dns_naptr_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 3403 - 4.1 Packet Format
+
+ The packet format for the NAPTR record is as follows
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ORDER |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PREFERENCE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / FLAGS /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / SERVICES /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / REGEXP /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / REPLACEMENT /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ <character-string> and <domain-name> as used here are defined in RFC 1035.
+ */
+ uint16_t order;
+ uint16_t preference;
+ char* flags;
+ char* services;
+ char* regexp;
+ char* replacement;
+}
+tnet_dns_naptr_t;
+
+TINYNET_API tnet_dns_naptr_t* tnet_dns_naptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_naptr_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_NAPTR_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_ns.c b/tinyNET/src/dns/tnet_dns_ns.c
new file mode 100644
index 0000000..a23426c
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_ns.c
@@ -0,0 +1,92 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_ns.c
+ * @brief DNS Name Server record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_ns.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+#include "tnet_dns_rr.h"
+
+/** Creates new DNS NS Resource Record.
+*/
+tnet_dns_ns_t* tnet_dns_ns_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_ns_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS NS]] object definition
+//
+static tsk_object_t* tnet_dns_ns_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_ns_t *ns = self;
+ if(ns){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+ uint16_t rdlength = tsk_va_arg_u16(*app);
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(ns), qtype_ns, qclass);
+ TNET_DNS_RR(ns)->name = tsk_strdup(name);
+ TNET_DNS_RR(ns)->rdlength = rdlength;
+ TNET_DNS_RR(ns)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* NSDNAME */
+ tnet_dns_rr_qname_deserialize(data, &(ns->nsdname), &offset);
+ }
+
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_ns_dtor(tsk_object_t * self)
+{
+ tnet_dns_ns_t *ns = self;
+ if(ns){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(ns));
+
+ TSK_FREE(ns->nsdname);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_ns_def_s =
+{
+ sizeof(tnet_dns_ns_t),
+ tnet_dns_ns_ctor,
+ tnet_dns_ns_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_ns_def_t = &tnet_dns_ns_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_ns.h b/tinyNET/src/dns/tnet_dns_ns.h
new file mode 100644
index 0000000..9a77f26
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_ns.h
@@ -0,0 +1,63 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_ns.h
+ * @brief DNS Name Server record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_NS_H
+#define TNET_DNS_RR_NS_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+
+/** DNS NS Resource Record.
+*/
+typedef struct tnet_dns_ns_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.3.11. NS RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NSDNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* nsdname;
+}
+tnet_dns_ns_t;
+
+TINYNET_API tnet_dns_ns_t* tnet_dns_ns_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ns_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_NS_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_opt.c b/tinyNET/src/dns/tnet_dns_opt.c
new file mode 100644
index 0000000..dab4fea
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_opt.c
@@ -0,0 +1,91 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_opt.c
+ * @brief DNS OPT pseudo-RR (RFC 2671).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_opt.h"
+
+
+
+/** Creates new DNS OPT Resource Record.
+*/
+tnet_dns_opt_t* tnet_dns_opt_create(tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dns_opt_def_t, payload_size);
+}
+
+
+
+
+
+
+
+
+
+//=================================================================================================
+// [[DNS OPT]] object definition
+//
+static tsk_object_t* tnet_dns_opt_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_opt_t *rr_opt = self;
+ if(rr_opt){
+ uint16_t payload_size = (uint16_t)va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(rr_opt), qtype_opt, qclass_any);
+
+ /*
+ NAME domain name empty (root domain)
+ TYPE u_int16_t OPT
+ CLASS u_int16_t sender's UDP payload size
+ TTL u_int32_t extended RCODE and flags
+ RDLEN u_int16_t describes RDATA
+ RDATA octet stream {attribute,value} pairs
+
+ */
+ TNET_DNS_RR(rr_opt)->qclass = payload_size;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_opt_dtor(tsk_object_t * self)
+{
+ tnet_dns_opt_t *rr_opt = self;
+ if(rr_opt){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(rr_opt));
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_opt_def_s =
+{
+ sizeof(tnet_dns_opt_t),
+ tnet_dns_opt_ctor,
+ tnet_dns_opt_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_opt_def_t = &tnet_dns_opt_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_opt.h b/tinyNET/src/dns/tnet_dns_opt.h
new file mode 100644
index 0000000..24485b9
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_opt.h
@@ -0,0 +1,54 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_opt.h
+ * @brief DNS OPT pseudo-RR (RFC 2671).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_OPT_H
+#define TNET_DNS_RR_OPT_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+/** DNS OPT Resource Record
+*/
+typedef struct tnet_dns_opt_s
+{
+ TNET_DECLARE_DNS_RR;
+}
+tnet_dns_opt_t;
+
+tnet_dns_opt_t* tnet_dns_opt_create(tsk_size_t payload_size);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_opt_def_t;
+
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_OPT_H */
diff --git a/tinyNET/src/dns/tnet_dns_ptr.c b/tinyNET/src/dns/tnet_dns_ptr.c
new file mode 100644
index 0000000..23b7733
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_ptr.c
@@ -0,0 +1,93 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_ptr.c
+ * @brief DNS Pointer record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_ptr.h"
+
+#include "../tnet_types.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+/** Creates new DNS PTR Resource Record.
+*/
+
+
+tnet_dns_ptr_t* tnet_dns_ptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void*data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_ptr_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS PTR]] object definition
+//
+static tsk_object_t* tnet_dns_ptr_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_ptr_t *ptr = self;
+ if(ptr){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+ uint16_t rdlength = tsk_va_arg_u16(*app);
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(ptr), qtype_ptr, qclass);
+ TNET_DNS_RR(ptr)->name = tsk_strdup(name);
+ TNET_DNS_RR(ptr)->rdlength = rdlength;
+ TNET_DNS_RR(ptr)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* PTRDNAME */
+ tnet_dns_rr_qname_deserialize(data, &(ptr->ptrdname), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_ptr_dtor(tsk_object_t * self)
+{
+ tnet_dns_ptr_t *ptr = self;
+ if(ptr){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(ptr));
+
+ TSK_FREE(ptr->ptrdname);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_ptr_def_s =
+{
+ sizeof(tnet_dns_ptr_t),
+ tnet_dns_ptr_ctor,
+ tnet_dns_ptr_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_ptr_def_t = &tnet_dns_ptr_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_ptr.h b/tinyNET/src/dns/tnet_dns_ptr.h
new file mode 100644
index 0000000..fc2cbdc
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_ptr.h
@@ -0,0 +1,61 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_ptr.h
+ * @brief DNS Pointer record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_PTR_H
+#define TNET_DNS_RR_PTR_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+TNET_BEGIN_DECLS
+
+
+/** DNS PTR Resource Record
+*/
+typedef struct tnet_dns_ptr_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.3.12. PTR RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / PTRDNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* ptrdname;
+}
+tnet_dns_ptr_t;
+
+tnet_dns_ptr_t* tnet_dns_ptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void*data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ptr_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_PTR_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_regexp.c b/tinyNET/src/dns/tnet_dns_regexp.c
new file mode 100644
index 0000000..5cafeb8
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_regexp.c
@@ -0,0 +1,286 @@
+
+/* #line 1 "./ragel/tnet_dns_regexp.rl" */
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_regexp.c
+ * @brief DNS Regex parser for NAPTR RR.
+ */
+#include "tnet_dns_regexp.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_ragel_state.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+/* === Ragel state machine === */
+
+/* #line 71 "./ragel/tnet_dns_regexp.rl" */
+
+
+/**
+* Apply @a regexp to @a e164num.
+* @param e164num Original E.164 number supplied by the user (only digits or '+' are accepted).
+* @param regexp A <character-string> containing a substitution expression that is
+* applied to the original string held by the client in order to
+* construct the next domain name to lookup. Example: "!^.*$!sip:bob@doubango.org!i".
+* @retval The final Internet address. It's up to the caller to free the string.
+*/
+char* tnet_dns_regex_parse(const char* e164num, const char* regexp)
+{
+ char* ret = tsk_null;
+ char* prefix = tsk_null;
+ const char* tag_start;
+ tsk_size_t e164len;
+
+ // Ragel
+ int cs = 0;
+ const char *p = tag_start = regexp;
+ const char *pe;
+ const char *eof;
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+
+/* #line 63 "./src/dns/tnet_dns_regexp.c" */
+static const char _tdns_machine_regexp_actions[] = {
+ 0, 1, 0, 1, 1, 1, 2, 2,
+ 0, 1, 2, 0, 2, 2, 2, 0,
+ 2, 3, 0, 3, 3, 0, 2
+};
+
+static const char _tdns_machine_regexp_key_offsets[] = {
+ 0, 0, 1, 2, 5, 6, 7, 8,
+ 9, 10, 11, 13, 15, 17, 19, 21,
+ 23, 25, 26, 27
+};
+
+static const char _tdns_machine_regexp_trans_keys[] = {
+ 33, 94, 40, 46, 92, 40, 46, 42,
+ 41, 36, 33, 33, 92, 33, 92, 48,
+ 57, 33, 92, 33, 92, 40, 42, 36,
+ 40, 40, 105, 0
+};
+
+static const char _tdns_machine_regexp_single_lengths[] = {
+ 0, 1, 1, 3, 1, 1, 1, 1,
+ 1, 1, 2, 2, 0, 2, 2, 2,
+ 2, 1, 1, 0
+};
+
+static const char _tdns_machine_regexp_range_lengths[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+static const char _tdns_machine_regexp_index_offsets[] = {
+ 0, 0, 2, 4, 8, 10, 12, 14,
+ 16, 18, 20, 23, 26, 28, 31, 34,
+ 37, 40, 42, 44
+};
+
+static const char _tdns_machine_regexp_trans_targs[] = {
+ 2, 0, 3, 0, 5, 15, 17, 4,
+ 5, 4, 6, 0, 7, 0, 8, 0,
+ 9, 0, 10, 0, 18, 12, 11, 18,
+ 12, 11, 13, 0, 18, 0, 14, 18,
+ 0, 14, 5, 16, 4, 9, 5, 4,
+ 5, 4, 19, 0, 0, 0
+};
+
+static const char _tdns_machine_regexp_trans_actions[] = {
+ 0, 0, 0, 0, 7, 1, 0, 1,
+ 3, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 10, 10, 10, 13,
+ 13, 13, 0, 0, 19, 0, 16, 5,
+ 0, 0, 3, 0, 0, 0, 3, 0,
+ 7, 1, 0, 0, 0, 0
+};
+
+static const int tdns_machine_regexp_start = 1;
+static const int tdns_machine_regexp_first_final = 18;
+static const int tdns_machine_regexp_error = 0;
+
+static const int tdns_machine_regexp_en_main = 1;
+
+
+/* #line 96 "./ragel/tnet_dns_regexp.rl" */
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+ (void)(eof);
+ (void)(tdns_machine_regexp_first_final);
+ (void)(tdns_machine_regexp_error);
+ (void)(tdns_machine_regexp_en_main);
+
+ if (!e164num) {
+ goto bail;
+ }
+
+ if (!regexp) {
+ ret = tsk_strdup(e164num);
+ goto bail;
+ }
+
+ e164len = (tsk_size_t)tsk_strlen(e164num);
+ pe = p + tsk_strlen(regexp);
+ eof = pe;
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+
+/* #line 148 "./src/dns/tnet_dns_regexp.c" */
+ {
+ cs = tdns_machine_regexp_start;
+ }
+
+/* #line 117 "./ragel/tnet_dns_regexp.rl" */
+
+/* #line 155 "./src/dns/tnet_dns_regexp.c" */
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _keys = _tdns_machine_regexp_trans_keys + _tdns_machine_regexp_key_offsets[cs];
+ _trans = _tdns_machine_regexp_index_offsets[cs];
+
+ _klen = _tdns_machine_regexp_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _tdns_machine_regexp_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += ((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ cs = _tdns_machine_regexp_trans_targs[_trans];
+
+ if ( _tdns_machine_regexp_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _tdns_machine_regexp_actions + _tdns_machine_regexp_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+/* #line 36 "./ragel/tnet_dns_regexp.rl" */
+ {
+ tag_start = p;
+ }
+ break;
+ case 1:
+/* #line 40 "./ragel/tnet_dns_regexp.rl" */
+ {
+ TSK_PARSER_SET_STRING(prefix);
+ }
+ break;
+ case 2:
+/* #line 44 "./ragel/tnet_dns_regexp.rl" */
+ {
+ int len = (int)(p - tag_start);
+ if (len) {
+ tsk_strncat(&ret, tag_start, len);
+ }
+ }
+ break;
+ case 3:
+/* #line 51 "./ragel/tnet_dns_regexp.rl" */
+ {
+ if (prefix) {
+ int prefixlen = (int)tsk_strlen(prefix);
+ tsk_strncat(&ret, e164num + prefixlen, (e164len - prefixlen));
+ }
+ }
+ break;
+/* #line 258 "./src/dns/tnet_dns_regexp.c" */
+ }
+ }
+
+_again:
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ _out: {}
+ }
+
+/* #line 118 "./ragel/tnet_dns_regexp.rl" */
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+
+ if (cs <
+/* #line 275 "./src/dns/tnet_dns_regexp.c" */
+18
+/* #line 120 "./ragel/tnet_dns_regexp.rl" */
+ ){
+ TSK_DEBUG_ERROR("regexp substitition failed.");
+ TSK_FREE(ret);
+ }
+
+bail:
+ TSK_FREE(prefix);
+
+ return ret;
+}
diff --git a/tinyNET/src/dns/tnet_dns_regexp.h b/tinyNET/src/dns/tnet_dns_regexp.h
new file mode 100644
index 0000000..d40abce
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_regexp.h
@@ -0,0 +1,41 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_regexp.h
+ * @brief DNS Regexp parser for NAPTR RR.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_REGEX_H
+#define TNET_DNS_REGEX_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+TINYNET_API char* tnet_dns_regex_parse(const char* e164num, const char* regexp);
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_REGEX_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_resolvconf.c b/tinyNET/src/dns/tnet_dns_resolvconf.c
new file mode 100644
index 0000000..a4a0fbf
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_resolvconf.c
@@ -0,0 +1,314 @@
+
+/* #line 1 "./ragel/tnet_dns_resolvconf.rl" */
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_resolvconf.c
+ * @brief Parser for "/etc/resolv.conf" file to retrive DNS servers.
+ */
+#include "tnet_dns_resolvconf.h"
+
+#include "tnet_utils.h"
+
+#include "dns/tnet_dns.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_ragel_state.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+
+/* === Ragel state machine === */
+
+/* #line 75 "./ragel/tnet_dns_resolvconf.rl" */
+
+
+/** Gets list of DNS servers from a conf file.
+* @param path Path of the conf file from which to retrieve the DNS servers.
+* should be @a "/etc/resolv.conf". You can adjust the value by modifying @ref TNET_RESOLV_CONF_PATH.<br>
+* If you are using <b>Android</b> and the resolv.conf file is missing, then run the following line in a command window: <br>
+* <i>ln -s /private/var/run/resolv.conf /etc/resolv.conf</i><br> If this fails, then try to manually add the file.
+* @retval List of DNS servers.
+*/
+tnet_addresses_L_t * tnet_dns_resolvconf_parse(const char* path)
+{
+ tnet_addresses_L_t* servers = tsk_null;
+ tnet_ip_t ip;
+ const char* fullpath = path;
+ const char* tag_start = tsk_null;
+ FILE* fd;
+ char* buf = tsk_null;
+
+ // Ragel
+ int cs = 0;
+ const char *p;
+ const char *pe;
+ const char *eof;
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+
+/* #line 69 "./src/dns/tnet_dns_resolvconf.c" */
+static const char _tdns_machine_resolvconf_actions[] = {
+ 0, 1, 0, 1, 1
+};
+
+static const char _tdns_machine_resolvconf_key_offsets[] = {
+ 0, 7, 8, 9, 12, 15, 15, 22,
+ 24, 27, 30, 33, 36, 39, 42, 45,
+ 48, 51, 52, 53, 56
+};
+
+static const char _tdns_machine_resolvconf_trans_keys[] = {
+ 10, 13, 32, 35, 59, 78, 110, 32,
+ 32, 10, 13, 32, 10, 13, 32, 10,
+ 13, 32, 35, 59, 78, 110, 10, 13,
+ 32, 65, 97, 32, 77, 109, 32, 69,
+ 101, 32, 83, 115, 32, 69, 101, 32,
+ 82, 114, 32, 86, 118, 32, 69, 101,
+ 32, 82, 114, 32, 32, 10, 13, 32,
+ 32, 35, 59, 78, 110, 0
+};
+
+static const char _tdns_machine_resolvconf_single_lengths[] = {
+ 7, 1, 1, 3, 3, 0, 7, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 1, 1, 3, 5
+};
+
+static const char _tdns_machine_resolvconf_range_lengths[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+};
+
+static const char _tdns_machine_resolvconf_index_offsets[] = {
+ 0, 8, 10, 12, 16, 20, 21, 29,
+ 32, 36, 40, 44, 48, 52, 56, 60,
+ 64, 68, 70, 72, 76
+};
+
+static const char _tdns_machine_resolvconf_indicies[] = {
+ 1, 1, 2, 3, 3, 4, 4, 0,
+ 5, 0, 5, 6, 7, 7, 8, 6,
+ 7, 7, 8, 9, 9, 1, 1, 5,
+ 3, 3, 4, 4, 0, 7, 7, 3,
+ 5, 10, 10, 0, 5, 11, 11, 0,
+ 5, 12, 12, 0, 5, 13, 13, 0,
+ 5, 14, 14, 0, 5, 15, 15, 0,
+ 5, 16, 16, 0, 5, 17, 17, 0,
+ 5, 18, 18, 0, 19, 0, 19, 20,
+ 22, 22, 23, 21, 2, 3, 3, 4,
+ 4, 0, 0
+};
+
+static const char _tdns_machine_resolvconf_trans_targs[] = {
+ 1, 6, 20, 7, 8, 2, 3, 0,
+ 4, 5, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 19, 0, 4
+};
+
+static const char _tdns_machine_resolvconf_trans_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 3, 3
+};
+
+static const int tdns_machine_resolvconf_start = 0;
+static const int tdns_machine_resolvconf_first_final = 0;
+static const int tdns_machine_resolvconf_error = -1;
+
+static const int tdns_machine_resolvconf_en_main = 0;
+
+
+/* #line 101 "./ragel/tnet_dns_resolvconf.rl" */
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+ (void)(eof);
+ (void)(tdns_machine_resolvconf_first_final);
+ (void)(tdns_machine_resolvconf_error);
+ (void)(tdns_machine_resolvconf_en_main);
+
+ if(tsk_strnullORempty(fullpath)){
+ fullpath = TNET_RESOLV_CONF_PATH;
+ }
+
+ /* Open the file and read all data */
+ if((fd = fopen(fullpath, "r"))){
+ long len;
+ fseek(fd, 0L, SEEK_END);
+ len = ftell(fd);
+ fseek(fd, 0L, SEEK_SET);
+ if (!(buf = (char*)tsk_calloc(len + 1, 1))) {
+ TSK_DEBUG_ERROR("Failed to allocate buffer with size = %ld", (len + 1));
+ goto bail;
+ }
+ fread(buf, 1, len, fd);
+ p = &buf[0];
+ pe = p + len + 1/*hack*/;
+ eof = pe;
+ fclose(fd);
+
+ buf[len] = '\n'; // hack to have perfect lines
+
+ servers = tsk_list_create();
+ }
+ else {
+#if ANDROID || defined(__APPLE__) /* TARGET_OS_IPHONE not defined for bsd libraries */
+ TSK_DEBUG_INFO("Failed to open [%s]. But don't panic, we have detected that you are using Google Android/iOS Systems.\n"
+ "You should look at the Progammer's Guide for more information.\n If you are not using DNS functions, don't worry about this warning.",
+ fullpath);
+#else
+ TSK_DEBUG_ERROR("Failed to open %s.", fullpath);
+#endif
+ goto bail;
+ }
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+
+/* #line 186 "./src/dns/tnet_dns_resolvconf.c" */
+ {
+ cs = tdns_machine_resolvconf_start;
+ }
+
+/* #line 144 "./ragel/tnet_dns_resolvconf.rl" */
+
+/* #line 193 "./src/dns/tnet_dns_resolvconf.c" */
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+_resume:
+ _keys = _tdns_machine_resolvconf_trans_keys + _tdns_machine_resolvconf_key_offsets[cs];
+ _trans = _tdns_machine_resolvconf_index_offsets[cs];
+
+ _klen = _tdns_machine_resolvconf_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _tdns_machine_resolvconf_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += ((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ _trans = _tdns_machine_resolvconf_indicies[_trans];
+ cs = _tdns_machine_resolvconf_trans_targs[_trans];
+
+ if ( _tdns_machine_resolvconf_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _tdns_machine_resolvconf_actions + _tdns_machine_resolvconf_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+/* #line 41 "./ragel/tnet_dns_resolvconf.rl" */
+ {
+ tag_start = p;
+ }
+ break;
+ case 1:
+/* #line 45 "./ragel/tnet_dns_resolvconf.rl" */
+ {
+ int len = (int)(p - tag_start);
+ if(len && len<=sizeof(ip)){
+ tnet_address_t *address;
+ memset(ip, '\0', sizeof(ip));
+ memcpy(ip, tag_start, len);
+ TSK_DEBUG_INFO("Adding DNS server = %s:%d", ip, TNET_DNS_SERVER_PORT_DEFAULT);
+
+ address = tnet_address_create(ip);
+ address->family = tnet_get_family(ip, TNET_DNS_SERVER_PORT_DEFAULT);
+ address->dnsserver = 1;
+ tsk_list_push_ascending_data(servers, (void**)&address);
+ }
+ }
+ break;
+/* #line 288 "./src/dns/tnet_dns_resolvconf.c" */
+ }
+ }
+
+_again:
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ }
+
+/* #line 145 "./ragel/tnet_dns_resolvconf.rl" */
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+
+ if (cs <
+/* #line 302 "./src/dns/tnet_dns_resolvconf.c" */
+0
+/* #line 147 "./ragel/tnet_dns_resolvconf.rl" */
+ ) {
+ TSK_DEBUG_ERROR("Failed to parse %s.", fullpath);
+ TSK_OBJECT_SAFE_FREE(servers);
+ }
+
+bail:
+ TSK_FREE(buf);
+ return servers;
+}
+
+
diff --git a/tinyNET/src/dns/tnet_dns_resolvconf.h b/tinyNET/src/dns/tnet_dns_resolvconf.h
new file mode 100644
index 0000000..5290c41
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_resolvconf.h
@@ -0,0 +1,43 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_resolvconf.h
+ * @brief Parser for "/etc/resolv.conf" file to retrive DNS servers.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RESOLVCONF_H
+#define TNET_DNS_RESOLVCONF_H
+
+#include "tinynet_config.h"
+
+#include "tnet_types.h"
+
+TNET_BEGIN_DECLS
+
+TINYNET_API tnet_addresses_L_t * tnet_dns_resolvconf_parse(const char* path);
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RESOLVCONF_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_rr.c b/tinyNET/src/dns/tnet_dns_rr.c
new file mode 100644
index 0000000..b74a31d
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_rr.c
@@ -0,0 +1,448 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_rr.c
+ * @brief DNS Resource Record (RFC 1034 and 1035).
+ *
+ */
+#include "tnet_dns_rr.h"
+
+#include "tnet_dns_a.h"
+#include "tnet_dns_aaaa.h"
+#include "tnet_dns_cname.h"
+#include "tnet_dns_mx.h"
+#include "tnet_dns_naptr.h"
+#include "tnet_dns_ns.h"
+#include "tnet_dns_opt.h"
+#include "tnet_dns_ptr.h"
+#include "tnet_dns_soa.h"
+#include "tnet_dns_srv.h"
+#include "tnet_dns_txt.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+#include "tsk_string.h"
+
+#include <string.h> /* strlen ... */
+
+
+/** Creates a new DNS RR.
+*/
+
+tnet_dns_rr_t* tnet_dns_rr_create()
+{
+ return tsk_object_new(tnet_dns_rr_def_t);
+}
+
+/** Initializes any DNS RR (either NAPTR or SRV ...).
+* @param rr The DNS RR to initialize.
+* @param qtype The type of the RR.
+* @param qclass The class of the RR.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_dns_rr_init(tnet_dns_rr_t *rr, tnet_dns_qtype_t qtype, tnet_dns_qclass_t qclass)
+{
+ if (rr){
+ if (!rr->initialized){
+ rr->qtype = qtype;
+ rr->qclass = qclass;
+
+ rr->initialized = tsk_true;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+/** Deinitializes any DNS RR (either NAPTR or SRV ...).
+* @param rr The DNS RR to deinitialize.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_dns_rr_deinit(tnet_dns_rr_t *rr)
+{
+ if (rr){
+ if (rr->initialized){
+ TSK_FREE(rr->name);
+ TSK_FREE(rr->rpdata);
+
+ rr->initialized = tsk_false;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+/** Deserialize <character-string>.
+*/
+int tnet_dns_rr_charstring_deserialize(const void* data, char** charstring, tsk_size_t *offset)
+{
+ /* RFC 1035 - 3.3. Standard RRs
+ <character-string> is a single length octet followed by that number of characters.
+ <character-string> is treated as binary information, and can be up to 256 characters in
+ length (including the length octet).
+ */
+ uint8_t* dataPtr = (((uint8_t*)data) + *offset);
+ uint8_t length = *dataPtr;
+
+ *charstring = tsk_strndup((const char*)(dataPtr + 1), length);
+ *offset += (1 + length);
+
+ return 0;
+}
+
+/** Deserializes a QName.
+*/
+int tnet_dns_rr_qname_deserialize(const void* data, char** name, tsk_size_t *offset)
+{
+ /* RFC 1035 - 4.1.4. Message compression
+
+ The pointer takes the form of a two octet sequence:
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | 1 1| OFFSET |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ uint8_t* dataPtr = (((uint8_t*)data) + *offset);
+ unsigned usingPtr = 0; /* Do not change. */
+
+ while (*dataPtr){
+ usingPtr = ((*dataPtr & 0xC0) == 0xC0);
+
+ if (usingPtr){
+ tsk_size_t ptr_offset = (*dataPtr & 0x3F);
+ ptr_offset = ptr_offset << 8 | *(dataPtr + 1);
+
+ *offset += 2;
+ return tnet_dns_rr_qname_deserialize(data, name, &ptr_offset);
+ }
+ else{
+ uint8_t length;
+
+ if (*name){
+ tsk_strcat(name, ".");
+ }
+
+ length = *dataPtr;
+ *offset += 1, dataPtr++;
+
+ tsk_strncat(name, (const char*)dataPtr, length);
+ *offset += length, dataPtr += length;
+ }
+ }
+
+ *offset += 1;
+
+ return 0;
+}
+
+//int tnet_dns_rr_qname_deserialize(const void* data, tsk_size_t size, char** name, tsk_size_t *offset)
+//{
+// /* RFC 1035 - 4.1.4. Message compression
+//
+// The pointer takes the form of a two octet sequence:
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | 1 1| OFFSET |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// */
+// uint8_t* dataPtr = (((uint8_t*)data) + *offset);
+// uint8_t* dataEnd = (dataPtr + size);
+// unsigned usingPtr = 0; /* Do not change. */
+// unsigned islast = 0;
+//
+// while(!islast)
+// {
+// usingPtr = ((*dataPtr & 0xC0) == 0xC0);
+//
+// if(usingPtr)
+// {
+// uint8_t *Ptr;
+// uint16_t ptr_offset = (*dataPtr & 0x3F);
+// ptr_offset = ptr_offset << 8 | *(dataPtr+1);
+// Ptr = ((uint8_t*)data) + ptr_offset;
+//
+// tnet_qname_label_parse(Ptr, (dataEnd - Ptr), name, &islast);
+// *offset += 2, dataPtr += 2;
+// }
+// else
+// {
+// tsk_size_t length = tnet_qname_label_parse(dataPtr, size, name, &islast);
+// *offset += length, dataPtr += length;
+// }
+// }
+//
+// *offset += usingPtr ? 0 : 1;
+//
+// return 0;
+//}
+
+/** Serializes a QName.
+*/
+int tnet_dns_rr_qname_serialize(const char* qname, tsk_buffer_t* output)
+{
+ /*
+ QNAME a domain name represented as a sequence of labels, where
+ each label consists of a length octet followed by that
+ number of octets. The domain name terminates with the
+ zero length octet for the null label of the root. Note
+ that this field may be an odd number of octets; no
+ padding is used.
+
+ Example: "doubango.com" ==> 8doubango3comNULL
+ */
+ static uint8_t null = 0;
+
+ if (qname){
+ char* saveptr;
+ char* _qname = tsk_strdup(qname);
+ char* label = tsk_strtok_r(_qname, ".", &saveptr);
+
+ while (label){
+ uint8_t length = (uint8_t)tsk_strlen(label);
+ tsk_buffer_append(output, &length, 1);
+ tsk_buffer_append(output, label, tsk_strlen(label));
+
+ label = tsk_strtok_r(tsk_null, ".", &saveptr);
+ }
+
+ TSK_FREE(_qname);
+ }
+
+ /* terminates domain name */
+ tsk_buffer_append(output, &null, 1);
+
+ return 0;
+}
+
+/** Deserializes a DNS RR.
+*/
+tnet_dns_rr_t* tnet_dns_rr_deserialize(const void* data, tsk_size_t size, tsk_size_t* offset)
+{
+ tnet_dns_rr_t *rr = tsk_null;
+ uint8_t* dataStart = (uint8_t*)data;
+ uint8_t* dataPtr = (dataStart + *offset);
+ //uint8_t* dataEnd = (dataPtr+size);
+ tnet_dns_qtype_t qtype;
+ tnet_dns_qclass_t qclass;
+ uint32_t ttl;
+ uint16_t rdlength;
+ char* qname = tsk_null;
+
+ /* Check validity */
+ if (!dataPtr || !size){
+ goto bail;
+ }
+
+ /* == Parse QNAME == */
+ tnet_dns_rr_qname_deserialize(dataStart, &qname, offset);
+ dataPtr = (dataStart + *offset);
+ /* == Parse QTYPE == */
+ qtype = (tnet_dns_qtype_t)tnet_ntohs_2(dataPtr);
+ dataPtr += 2, *offset += 2;
+ /* == Parse QCLASS == */
+ qclass = (tnet_dns_qclass_t)tnet_ntohs_2(dataPtr);
+ dataPtr += 2, *offset += 2;
+ /* == Parse TTL == */
+ ttl = (uint32_t)tnet_htonl_2(dataPtr);
+ dataPtr += 4, *offset += 4;
+ /* == Parse RDLENGTH == */
+ rdlength = tnet_ntohs_2(dataPtr);
+ dataPtr += 2, *offset += 2;
+
+ switch (qtype){
+ case qtype_a:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_a_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_aaaa:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_aaaa_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_cname:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_cname_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_mx:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_mx_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_naptr:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_naptr_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_ns:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_ns_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_opt:
+ {
+ unsigned payload_size = qclass;
+ rr = (tnet_dns_rr_t *)tnet_dns_opt_create(payload_size);
+ break;
+ }
+
+ case qtype_ptr:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_ptr_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_soa:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_soa_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_srv:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_srv_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_txt:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_txt_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ default:
+ {
+ TSK_DEBUG_ERROR("NOT IMPLEMENTED");
+ break;
+ }
+ }
+
+bail:
+ TSK_FREE(qname);
+
+ *offset += rdlength;
+ return rr;
+}
+
+/** Serializes a DNS RR.
+*/
+int tnet_dns_rr_serialize(const tnet_dns_rr_t* rr, tsk_buffer_t *output)
+{
+ if (!rr || !output){
+ return -1;
+ }
+
+ /*=== NAME ===*/
+ {
+ tnet_dns_rr_qname_serialize(rr->name, output);
+ }
+
+ /*=== TYPE ===*/
+ {
+ uint16_t qtype = tnet_htons(rr->qtype);
+ tsk_buffer_append(output, &(qtype), 2);
+ }
+
+ /*=== CLASS ===*/
+ {
+ uint16_t qclass = tnet_htons(rr->qclass);
+ tsk_buffer_append(output, &(qclass), 2);
+ }
+
+ /*=== TTL ===*/
+ {
+ uint32_t ttl = (uint32_t)tnet_htonl(rr->ttl);
+ tsk_buffer_append(output, &(ttl), 4);
+ }
+
+ /*=== RDLENGTH ===*/
+ {
+ uint16_t length = tnet_htons(rr->rdlength);
+ tsk_buffer_append(output, &(length), 2);
+ }
+
+ /*=== RDATA : Request never contains data
+ ===*/
+ if (!rr->rpdata){
+ goto done;
+ }
+
+ switch (rr->qtype){
+ case qtype_a:
+ case qtype_aaaa:
+ case qtype_cname:
+ case qtype_mx:
+ case qtype_naptr:
+ case qtype_ns:
+ case qtype_opt:
+ case qtype_ptr:
+ case qtype_soa:
+ case qtype_srv:
+ case qtype_txt:
+ default:
+ {
+ TSK_DEBUG_WARN("DNS Request should not contains RDATA (not supported).");
+ break;
+ }
+ }
+
+done:
+ return 0;
+}
+
+
+//=================================================================================================
+// [[DNS RR]] object definition
+//
+static tsk_object_t* tnet_dns_rr_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_rr_t *rr = self;
+ if (rr){
+ tnet_dns_rr_init(rr, qtype_any, qclass_any);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_rr_dtor(tsk_object_t * self)
+{
+ tnet_dns_rr_t *rr = self;
+ if (rr){
+ tnet_dns_rr_deinit(rr);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_rr_def_s =
+{
+ sizeof(tnet_dns_rr_t),
+ tnet_dns_rr_ctor,
+ tnet_dns_rr_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_rr_def_t = &tnet_dns_rr_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_rr.h b/tinyNET/src/dns/tnet_dns_rr.h
new file mode 100644
index 0000000..f4a1b6b
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_rr.h
@@ -0,0 +1,171 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_rr.h
+ * @brief DNS Resource Record (RFCS 1034 and 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef TNET_DNS_RR_H
+#define TNET_DNS_RR_H
+
+#include "tinynet_config.h"
+
+#include "tsk_list.h"
+#include "tsk_buffer.h"
+
+/** @def TNET_DNS_RR
+* Converts any DNS RR to a pointer to @ref tnet_dns_rr_t.
+* @retval A pointer to @ref tnet_dns_rr_t object.
+*/
+TNET_BEGIN_DECLS
+
+#define TNET_DNS_RR(self) ((tnet_dns_rr_t*)(self))
+
+/** RFC 1035 - 3.2.2. TYPE values
+* @sa http://en.wikipedia.org/wiki/List_of_DNS_record_types
+*/
+typedef enum tnet_dns_qtype_e
+{
+ qtype_a = 1, /**< A 1 a host address */
+ qtype_ns = 2, /**< NS 2 an authoritative name server */
+ qtype_md = 3, /**< MD 3 a mail destination (Obsolete - use MX) */
+ qtype_mf = 4, /**< MF 4 a mail forwarder (Obsolete - use MX) */
+ qtype_cname = 5, /**< CNAME 5 the canonical name for an alias */
+ qtype_soa = 6, /**< SOA 6 marks the start of a zone of authority */
+ qtype_mb = 7, /**< MB 7 a mailbox domain name (EXPERIMENTAL) */
+ qtype_mg = 8, /**< MG 8 a mail group member (EXPERIMENTAL) */
+ qtype_mr = 9, /**< MR 9 a mail rename domain name (EXPERIMENTAL) */
+ qtype_null = 10, /**< NULL 10 a null RR (EXPERIMENTAL) */
+ qtype_wks = 11, /**< WKS 11 a well known service description */
+ qtype_ptr = 12, /**< PTR 12 a domain name pointer */
+ qtype_hinfo = 13, /**< HINFO 13 host information */
+ qtype_minfo = 14, /**< MINFO 14 mailbox or mail list information */
+ qtype_mx = 15, /**< MX 15 mail exchange */
+ qtype_txt = 16, /**< TXT 16 text strings */
+
+ qtype_aaaa = 28, /**< AAAA 28 IPv6 host address */
+
+ qtype_srv = 33, /**< SRV 33 Service locator */
+
+ qtype_naptr = 35, /**< NAPTR 35 Naming Authority Pointer */
+
+ qtype_opt = 41, /**< OPT 41 Option */
+
+ qtype_ipseckey = 45,/**< IPSECKEY 45 IPSEC Key */
+
+ qtype_spf = 99, /**< SPF 99 SPF record */
+
+ qtype_any = 255 /**< * 255 A request for all records (3.2.3. QTYPE values)*/
+}
+tnet_dns_qtype_t;
+
+/** RFC 1035 - 3.2.4. CLASS values
+*/
+typedef enum tnet_dns_qclass_e
+{
+ qclass_in = 1, /**< IN 1 the Internet */
+ qclass_ics = 2, /**< CS 2 the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
+ qclass_ch = 3, /**< CH 3 the CHAOS class */
+ qclass_hs = 4, /**< HS 4 Hesiod [Dyer 87] */
+
+ qclass_any = 255 /**< * 255 any class (3.2.5. QCLASS values) */
+}
+tnet_dns_qclass_t;
+
+/** RFC 1034 (3.6. Resource Records) and 1035 (3.2.1. Format)
+*/
+typedef struct tnet_dns_rr_s
+{
+ TSK_DECLARE_OBJECT;
+
+ /* RFC 1035 - 3.2.1. Format
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+
+ tsk_bool_t initialized;
+
+ /** An owner name, i.e., the name of the node to which this resource record pertains. */
+ char* name;
+
+ /** Two octets containing one of the RR TYPE codes. */
+ tnet_dns_qtype_t qtype;
+
+ /** Two octets containing one of the RR CLASS codes. */
+ tnet_dns_qclass_t qclass;
+
+ /** A 32 bit signed integer that specifies the time interval (seconds) that the resource record may be cached before the source
+ of the information should again be consulted.
+ Zero values are interpreted to mean that the RR can only be used for the transaction in progress, and should not be cached.
+ For example, SOA records are always distributed with a zero TTL to prohibit caching. Zero values can also be used for extremely volatile data. */
+ int32_t ttl;
+
+ /** An unsigned 16 bit integer that specifies the length in octets of the RDATA field. */
+ uint16_t rdlength;
+
+ /** A variable length string of octets that describes the resource.
+ The format of this information varies according to the TYPE and CLASS of the resource record.*/
+ void *rpdata;
+}
+tnet_dns_rr_t;
+
+#define TNET_DECLARE_DNS_RR tnet_dns_rr_t dns_rr
+
+typedef tsk_list_t tnet_dns_rrs_L_t; /**< List of @ref tnet_dns_rr_t elements. */
+
+int tnet_dns_rr_init(tnet_dns_rr_t *rr, tnet_dns_qtype_t qtype, tnet_dns_qclass_t qclass);
+int tnet_dns_rr_deinit(tnet_dns_rr_t *rr);
+
+int tnet_dns_rr_charstring_deserialize(const void* data, char** name, tsk_size_t *offset);
+
+int tnet_dns_rr_qname_deserialize(const void* data, char** name, tsk_size_t *offset);
+int tnet_dns_rr_qname_serialize(const char* qname, tsk_buffer_t* output);
+
+tnet_dns_rr_t* tnet_dns_rr_deserialize(const void* data, tsk_size_t size, tsk_size_t* offset);
+int tnet_dns_rr_serialize(const tnet_dns_rr_t* rr, tsk_buffer_t *output);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_rr_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_H */
diff --git a/tinyNET/src/dns/tnet_dns_soa.c b/tinyNET/src/dns/tnet_dns_soa.c
new file mode 100644
index 0000000..a1844f4
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_soa.c
@@ -0,0 +1,108 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_soa.c
+ * @brief DNS Start Of Authority record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_soa.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+tnet_dns_soa_t* tnet_dns_soa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_soa_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS SOA]] object definition
+//
+static tsk_object_t* tnet_dns_soa_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_soa_t *soa = self;
+ if(soa){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+ uint16_t rdlength = tsk_va_arg_u16(*app);
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(soa), qtype_soa, qclass);
+ TNET_DNS_RR(soa)->name = tsk_strdup(name);
+ TNET_DNS_RR(soa)->rdlength = rdlength;
+ TNET_DNS_RR(soa)->ttl = ttl;
+
+ if(rdlength)
+ { // ==> DESERIALIZATION
+ /* MNAME */
+ tnet_dns_rr_qname_deserialize(data, &(soa->mname), &offset);
+ /* RNAME */
+ tnet_dns_rr_qname_deserialize(data, &(soa->rname), &offset);
+ /* SERIAL */
+ soa->serial = tnet_htonl_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* REFRESH */
+ soa->refresh = tnet_htonl_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* RETRY */
+ soa->retry = tnet_htonl_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* EXPIRE */
+ soa->expire = tnet_htonl_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* MINIMUM */
+ soa->minimum = tnet_htonl_2(((uint8_t*)data) + offset),
+ offset += 2;
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_soa_dtor(tsk_object_t * self)
+{
+ tnet_dns_soa_t *soa = self;
+ if(soa){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(soa));
+
+ TSK_FREE(soa->mname);
+ TSK_FREE(soa->rname);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_soa_def_s =
+{
+ sizeof(tnet_dns_soa_t),
+ tnet_dns_soa_ctor,
+ tnet_dns_soa_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_soa_def_t = &tnet_dns_soa_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_soa.h b/tinyNET/src/dns/tnet_dns_soa.h
new file mode 100644
index 0000000..298e907
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_soa.h
@@ -0,0 +1,82 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_soa.h
+ * @brief DNS Start Of Authority record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_SOA_H
+#define TNET_DNS_RR_SOA_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+TNET_BEGIN_DECLS
+
+typedef struct tnet_dns_soa_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.3.13. SOA RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | SERIAL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | REFRESH |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RETRY |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | EXPIRE |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | MINIMUM |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* mname;
+ char* rname;
+ uint32_t serial;
+ uint32_t refresh;
+ uint32_t retry;
+ uint32_t expire;
+ uint32_t minimum;
+}
+tnet_dns_soa_t;
+
+tnet_dns_soa_t* tnet_dns_soa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_soa_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_SOA_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_srv.c b/tinyNET/src/dns/tnet_dns_srv.c
new file mode 100644
index 0000000..4625d68
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_srv.c
@@ -0,0 +1,133 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_srv.c
+ * @brief DNS SeRVice locator record - RR - (RFC 2782).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_srv.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+/** Creates new DNS SRV Resource Record.
+*/
+tnet_dns_srv_t* tnet_dns_srv_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_srv_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS SRV]] object definition
+//
+static tsk_object_t* tnet_dns_srv_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_srv_t *srv = self;
+ if(srv){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+ uint16_t rdlength = tsk_va_arg_u16(*app);
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(srv), qtype_srv, qclass);
+ TNET_DNS_RR(srv)->name = tsk_strdup(name);
+ TNET_DNS_RR(srv)->rdlength = rdlength;
+ TNET_DNS_RR(srv)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* Priority */
+ srv->priority = tnet_ntohs_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* Weight */
+ srv->weight = tnet_ntohs_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* Port */
+ srv->port = tnet_ntohs_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* Target */
+ tnet_dns_rr_qname_deserialize(data, &(srv->target), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_srv_dtor(tsk_object_t * self)
+{
+ tnet_dns_srv_t *srv = self;
+ if(srv){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(srv));
+
+ TSK_FREE(srv->target);
+ }
+ return self;
+}
+
+static int tnet_dns_srv_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
+{
+ const tnet_dns_rr_t* rr1 = obj1;
+ const tnet_dns_rr_t* rr2 = obj2;
+
+ if(rr1 && rr2 && (rr1->qtype==qtype_srv) && (rr2->qtype==qtype_srv)){
+ const tnet_dns_srv_t* srv1 = (tnet_dns_srv_t*)rr1;
+ const tnet_dns_srv_t* srv2 = (tnet_dns_srv_t*)rr2;
+
+ /* Compare priorities. */
+ if(srv1->priority < srv2->priority){ /* Lowest priority is tried first. */
+ return 1;
+ }
+ else if(srv1->priority > srv2->priority){
+ return -1;
+ }
+
+ /* Compare weight */
+ if(srv1->weight > srv2->weight){
+ return 1;
+ }
+ else if(srv1->weight < srv2->weight){
+ return -1;
+ }
+
+ return 0;
+ }
+ else{
+ return -1;
+ }
+}
+
+static const tsk_object_def_t tnet_dns_srv_def_s =
+{
+ sizeof(tnet_dns_srv_t),
+ tnet_dns_srv_ctor,
+ tnet_dns_srv_dtor,
+ tnet_dns_srv_cmp,
+};
+const tsk_object_def_t *tnet_dns_srv_def_t = &tnet_dns_srv_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_srv.h b/tinyNET/src/dns/tnet_dns_srv.h
new file mode 100644
index 0000000..c8cc94d
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_srv.h
@@ -0,0 +1,59 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_srv.h
+ * @brief DNS SeRVice locator record - RR - (RFC 2782).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_SRV_H
+#define TNET_DNS_RR_SRV_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+/** DNS SRV Resource Record
+*/
+typedef struct tnet_dns_srv_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+ char* target;
+}
+tnet_dns_srv_t;
+
+tnet_dns_srv_t* tnet_dns_srv_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_srv_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_SRV_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_txt.c b/tinyNET/src/dns/tnet_dns_txt.c
new file mode 100644
index 0000000..9d152e9
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_txt.c
@@ -0,0 +1,92 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_txt.c
+ * @brief DNS TeXT record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_dns_txt.h"
+
+#include "../tnet_types.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+/** Creates new DNS TXT Resource Record.
+*/
+
+tnet_dns_txt_t* tnet_dns_txt_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_txt_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS TXT]] object definition
+//
+static tsk_object_t* tnet_dns_txt_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_txt_t *txt = self;
+ if(txt){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+ uint16_t rdlength = tsk_va_arg_u16(*app);
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(txt), qtype_txt, qclass);
+ TNET_DNS_RR(txt)->name = tsk_strdup(name);
+ TNET_DNS_RR(txt)->rdlength = rdlength;
+ TNET_DNS_RR(txt)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* TXT-DATA */
+ tnet_dns_rr_charstring_deserialize(data, &(txt->txt_data), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_txt_dtor(tsk_object_t * self)
+{
+ tnet_dns_txt_t *txt = self;
+ if(txt){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(txt));
+
+ TSK_FREE(txt->txt_data);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_txt_def_s =
+{
+ sizeof(tnet_dns_txt_t),
+ tnet_dns_txt_ctor,
+ tnet_dns_txt_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_txt_def_t = &tnet_dns_txt_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_txt.h b/tinyNET/src/dns/tnet_dns_txt.h
new file mode 100644
index 0000000..05f54d9
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_txt.h
@@ -0,0 +1,61 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_dns_txt.h
+ * @brief DNS TeXT record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_DNS_RR_TXT_H
+#define TNET_DNS_RR_TXT_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+/** DNS TXT Resource Record
+*/
+typedef struct tnet_dns_txt_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.3.14. TXT RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / TXT-DATA /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* txt_data;
+}
+tnet_dns_txt_t;
+
+tnet_dns_txt_t* tnet_dns_txt_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_txt_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_TXT_H */
+
diff --git a/tinyNET/src/ice/tnet_ice.c b/tinyNET/src/ice/tnet_ice.c
new file mode 100644
index 0000000..196009b
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice.c
@@ -0,0 +1,27 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_ice.c
+ * @brief Interactive Connectivity Establishment (ICE) implementation as per 'draft-ietf-mmusic-ice-19' and 'draft-ietf-mmusic-ice-tcp-08'.
+ * http://tools.ietf.org/html/draft-ietf-mmusic-ice-19
+ * http://tools.ietf.org/html/draft-ietf-mmusic-ice-tcp-08
+ *
+ */
+#include "tnet_ice.h"
diff --git a/tinyNET/src/ice/tnet_ice.h b/tinyNET/src/ice/tnet_ice.h
new file mode 100644
index 0000000..daffd08
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice.h
@@ -0,0 +1,37 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_ice.h
+ * @brief Interactive Connectivity Establishment (ICE) implementation as per 'draft-ietf-mmusic-ice-19' and 'draft-ietf-mmusic-ice-tcp-08'.
+ * http://tools.ietf.org/html/draft-ietf-mmusic-ice-19
+ * http://tools.ietf.org/html/draft-ietf-mmusic-ice-tcp-08
+ *
+ */
+#ifndef TNET_ICE_H
+#define TNET_ICE_H
+
+#include "../tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+
+TNET_END_DECLS
+
+#endif /* TNET_ICE_H */
diff --git a/tinyNET/src/ice/tnet_ice_candidate.c b/tinyNET/src/ice/tnet_ice_candidate.c
new file mode 100644
index 0000000..6dba738
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice_candidate.c
@@ -0,0 +1,660 @@
+/*
+ * Copyright (C) 2012-2015 Mamadou DIOP
+ * Copyright (C) 2012-2015 Doubango Telecom <http://www.doubango.org>.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+#include "tnet_ice_candidate.h"
+#include "tnet_ice_utils.h"
+#include "tnet_utils.h"
+#include "turn/tnet_turn_session.h"
+
+#include "tsk_md5.h"
+#include "tsk_memory.h"
+#include "tsk_list.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+static int _tnet_ice_candidate_tostring(
+ uint8_t* foundation,
+ uint32_t comp_id,
+ const char* transport_str,
+ uint32_t priority,
+ const char* connection_addr,
+ tnet_port_t port,
+ const char* cand_type_str,
+ const tsk_params_L_t *extension_att_list,
+ char** output);
+static const char* _tnet_ice_candidate_get_foundation(tnet_ice_cand_type_t type);
+static tnet_stun_pkt_t * _tnet_ice_candidate_stun_create_bind_request(tnet_ice_candidate_t* self, const char* username, const char* password);
+static tsk_bool_t _tnet_ice_candidate_stun_transac_id_equals(const tnet_stun_transac_id_t id1, const tnet_stun_transac_id_t id2);
+static const char* _tnet_ice_candidate_get_transport_str(tnet_socket_type_t transport_e);
+static tnet_socket_type_t _tnet_ice_candidate_get_transport_type(tsk_bool_t ipv6, const char* transport_str);
+static const char* _tnet_ice_candidate_get_candtype_str(tnet_ice_cand_type_t candtype_e);
+static tnet_ice_cand_type_t _tnet_ice_candtype_get_transport_type(const char* candtype_str);
+
+static tsk_object_t* tnet_ice_candidate_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_ice_candidate_t *candidate = self;
+ if (candidate){
+ candidate->extension_att_list = tsk_list_create();
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_ice_candidate_dtor(tsk_object_t * self)
+{
+ tnet_ice_candidate_t *candidate = self;
+ if (candidate){
+ TSK_SAFE_FREE(candidate->transport_str);
+ TSK_SAFE_FREE(candidate->cand_type_str);
+ TSK_OBJECT_SAFE_FREE(candidate->extension_att_list);
+ TSK_OBJECT_SAFE_FREE(candidate->socket);
+
+
+ TSK_SAFE_FREE(candidate->stun.nonce);
+ TSK_SAFE_FREE(candidate->stun.realm);
+ TSK_SAFE_FREE(candidate->stun.srflx_addr);
+
+ TSK_SAFE_FREE(candidate->turn.relay_addr);
+ TSK_OBJECT_SAFE_FREE(candidate->turn.ss);
+
+ TSK_SAFE_FREE(candidate->ufrag);
+ TSK_SAFE_FREE(candidate->pwd);
+
+ TSK_SAFE_FREE(candidate->tostring);
+ }
+ return self;
+}
+
+static int tnet_ice_candidate_cmp(const tsk_object_t *_s1, const tsk_object_t *_s2)
+{
+ const tnet_ice_candidate_t *c1 = _s1;
+ const tnet_ice_candidate_t *c2 = _s2;
+
+ if (c1 && c2){
+ return (int)(c1->priority - c2->priority);
+ }
+ else if (!c1 && !c2) return 0;
+ else return -1;
+}
+
+static const tsk_object_def_t tnet_ice_candidate_def_s =
+{
+ sizeof(tnet_ice_candidate_t),
+ tnet_ice_candidate_ctor,
+ tnet_ice_candidate_dtor,
+ tnet_ice_candidate_cmp,
+};
+
+tnet_ice_candidate_t* tnet_ice_candidate_create(tnet_ice_cand_type_t type_e, tnet_socket_t* socket, tsk_bool_t is_ice_jingle, tsk_bool_t is_rtp, tsk_bool_t is_video, const char* ufrag, const char* pwd, const char *foundation)
+{
+ tnet_ice_candidate_t* candidate;
+
+ if (!(candidate = tsk_object_new(&tnet_ice_candidate_def_s))){
+ TSK_DEBUG_ERROR("Failed to create candidate");
+ return tsk_null;
+ }
+
+ candidate->type_e = type_e;
+ candidate->socket = tsk_object_ref(socket);
+ candidate->local_pref = 0xFFFF;
+ candidate->is_ice_jingle = is_ice_jingle;
+ candidate->is_rtp = is_rtp;
+ candidate->is_video = is_video;
+ candidate->comp_id = is_rtp ? TNET_ICE_CANDIDATE_COMPID_RTP : TNET_ICE_CANDIDATE_COMPID_RTCP;
+ if (foundation){
+ memcpy(candidate->foundation, foundation, TSK_MIN(tsk_strlen(foundation), TNET_ICE_CANDIDATE_FOUND_SIZE_PREF));
+ }
+ else{
+ tnet_ice_utils_compute_foundation((char*)candidate->foundation, TSK_MIN(sizeof(candidate->foundation), TNET_ICE_CANDIDATE_FOUND_SIZE_PREF));
+ }
+ candidate->priority = tnet_ice_utils_get_priority(candidate->type_e, candidate->local_pref, candidate->is_rtp);
+ if (candidate->socket){
+ memcpy(candidate->connection_addr, candidate->socket->ip, sizeof(candidate->socket->ip));
+ candidate->port = candidate->socket->port;
+ candidate->transport_e = socket->type;
+ }
+ tnet_ice_candidate_set_credential(candidate, ufrag, pwd);
+
+ return candidate;
+}
+
+// @param str e.g. "1 1 udp 1 192.168.196.1 57806 typ host name video_rtcp network_name {0C0137CC-DB78-46B6-9B6C-7E097FFA79FE} username StFEVThMK2DHThkv password qkhKUDr4WqKRwZTo generation 0"
+tnet_ice_candidate_t* tnet_ice_candidate_parse(const char* str)
+{
+ char *v, *copy, *saveptr;
+ int32_t k;
+ tnet_ice_candidate_t* candidate;
+
+ if (tsk_strnullORempty(str)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ if (!(candidate = tsk_object_new(&tnet_ice_candidate_def_s))){
+ TSK_DEBUG_ERROR("Failed to create candidate");
+ return tsk_null;
+ }
+
+ k = 0;
+ copy = tsk_strdup(str);
+ v = tsk_strtok_r(copy, " ", &saveptr);
+
+ while (v){
+ switch (k){
+ case 0:
+ {
+ memcpy(candidate->foundation, v, TSK_MIN(tsk_strlen(v), sizeof(candidate->foundation)));
+ break;
+ }
+ case 1:
+ {
+ candidate->comp_id = atoi(v);
+ break;
+ }
+ case 2:
+ {
+ candidate->transport_str = tsk_strdup(v);
+ break;
+ }
+ case 3:
+ {
+ candidate->priority = atoi(v);
+ break;
+ }
+ case 4:
+ {
+ memcpy(candidate->connection_addr, v, TSK_MIN(tsk_strlen(v), sizeof(candidate->connection_addr)));
+ break;
+ }
+ case 5:
+ {
+ tnet_family_t family;
+ candidate->port = atoi(v);
+ family = tnet_get_family(candidate->connection_addr, candidate->port);
+ candidate->transport_e = _tnet_ice_candidate_get_transport_type((family == AF_INET6), candidate->transport_str);
+ break;
+ }
+ case 6:
+ {
+ v = tsk_strtok_r(tsk_null, " ", &saveptr);
+ tsk_strupdate(&candidate->cand_type_str, v);
+ candidate->type_e = _tnet_ice_candtype_get_transport_type(v);
+ break;
+ }
+ default:
+ {
+ const char* name = v;
+ const char* value = (v = tsk_strtok_r(tsk_null, " ", &saveptr));
+ tsk_param_t* param = tsk_param_create(name, value);
+ if (param){
+ tsk_list_push_back_data(candidate->extension_att_list, (void**)&param);
+ }
+ break;
+ }
+ }
+
+ ++k;
+ v = tsk_strtok_r(tsk_null, " ", &saveptr);
+ }
+
+ if (k < 6){
+ TSK_DEBUG_ERROR("Failed to parse: %s", str);
+ TSK_OBJECT_SAFE_FREE(candidate);
+ }
+ TSK_FREE(copy);
+
+ return candidate;
+}
+
+int tnet_ice_candidate_set_credential(tnet_ice_candidate_t* self, const char* ufrag, const char* pwd)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_strupdate(&self->ufrag, ufrag);
+ tsk_strupdate(&self->pwd, pwd);
+
+ return 0;
+}
+
+int tnet_ice_candidate_set_rflx_addr(tnet_ice_candidate_t* self, const char* addr, tnet_port_t port)
+{
+ if (!self || !addr || !port){
+ TSK_DEBUG_ERROR("Invalid argument");
+ return -1;
+ }
+ memset(self->connection_addr, 0, sizeof(self->connection_addr));
+ memcpy(self->connection_addr, addr, TSK_MIN(tsk_strlen(addr), sizeof(self->connection_addr)));
+ self->port = port;
+ return 0;
+}
+
+const char* tnet_ice_candidate_get_att_value(const tnet_ice_candidate_t* self, const char* att_name)
+{
+ if (!self || !att_name){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+ return tsk_params_get_param_value(self->extension_att_list, att_name);
+}
+
+int tnet_ice_candidate_set_local_pref(tnet_ice_candidate_t* self, uint16_t local_pref)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->local_pref = local_pref;
+ self->priority = tnet_ice_utils_get_priority(self->type_e, self->local_pref, self->is_rtp);
+ return 0;
+}
+
+const char* tnet_ice_candidate_tostring(tnet_ice_candidate_t* self)
+{
+ const char* _transport_str;
+ char __str[255]; // always allocated: bad idea :(
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid argument");
+ return tsk_null;
+ }
+
+ if (self->type_e == tnet_ice_cand_type_relay && self->turn.ss) {
+ enum tnet_turn_transport_e e_req_transport = tnet_turn_transport_udp;
+ tnet_turn_session_get_req_transport(self->turn.ss, &e_req_transport);
+ _transport_str = (e_req_transport == tnet_turn_transport_tcp) ? "tcp" : "udp";
+ }
+ else {
+ _transport_str = self->transport_str ? self->transport_str : _tnet_ice_candidate_get_transport_str(self->transport_e);
+ if (self->is_ice_jingle){
+ tsk_size_t i, s = tsk_strlen(_transport_str);
+ memset(__str, 0, sizeof(__str));
+ for (i = 0; i < s && i < sizeof(__str) / sizeof(__str[0]); ++i){
+ __str[i] = tolower(_transport_str[i]);
+ }
+ _transport_str = &__str[0];
+ }
+ }
+
+ _tnet_ice_candidate_tostring(
+ self->foundation,
+ self->comp_id,
+ _transport_str,
+ self->priority,
+ (tsk_strnullORempty(self->connection_addr) && self->socket) ? self->socket->ip : self->connection_addr,
+ (self->port <= 0 && self->socket) ? self->socket->port : self->port,
+ self->cand_type_str ? self->cand_type_str : _tnet_ice_candidate_get_candtype_str(self->type_e),
+ self->extension_att_list,
+ &self->tostring);
+
+ /* <rel-addr> and <rel-port>: convey transport addresses related to the
+ candidate, useful for diagnostics and other purposes. <rel-addr>
+ and <rel-port> MUST be present for server reflexive, peer
+ reflexive, and relayed candidates. */
+ switch (self->type_e){
+ case tnet_ice_cand_type_srflx:
+ case tnet_ice_cand_type_prflx:
+ case tnet_ice_cand_type_relay:
+ {
+ if (self->socket){ // when called from the browser(IE, Safari, Opera or Firefox) webrtc4all
+ tsk_strcat_2(&self->tostring, " raddr %s rport %d", self->socket->ip, self->socket->port);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ // To ease debugging
+ if (self->socket) {
+ tsk_strcat_2(&self->tostring, " tr %s", _tnet_ice_candidate_get_transport_str(self->socket->type));
+ if (self->type_e == tnet_ice_cand_type_relay && self->turn.ss) {
+ tnet_socket_t* turn_sock = tsk_null;
+ if (tnet_turn_session_get_socket_local(self->turn.ss, &turn_sock) == 0 && turn_sock) {
+ tsk_strcat_2(&self->tostring, " fd %d", turn_sock->fd);
+ }
+ TSK_OBJECT_SAFE_FREE(turn_sock);
+ }
+ else {
+ tsk_strcat_2(&self->tostring, " fd %d", self->socket->fd);
+ }
+ }
+
+ // WebRTC (Chrome) specific
+ if (self->is_ice_jingle) {
+ if (!tsk_params_have_param(self->extension_att_list, "name")){
+ tsk_strcat_2(&self->tostring, " name %s", self->is_rtp ? (self->is_video ? "video_rtp" : "rtp") : (self->is_video ? "video_rtcp" : "rtcp"));
+ }
+ if (!tsk_params_have_param(self->extension_att_list, "username")){
+ tsk_strcat_2(&self->tostring, " username %s", self->ufrag);
+ }
+ if (!tsk_params_have_param(self->extension_att_list, "password")){
+ tsk_strcat_2(&self->tostring, " password %s", self->pwd);
+ }
+ if (!tsk_params_have_param(self->extension_att_list, "network_name")){
+ tsk_strcat_2(&self->tostring, " network_name %s", "{9EBBE687-CCE6-42D3-87F5-B57BB30DEE23}");
+ }
+ if (!tsk_params_have_param(self->extension_att_list, "generation")){
+ tsk_strcat_2(&self->tostring, " generation %s", "0");
+ }
+ }
+
+ return self->tostring;
+}
+
+int tnet_ice_candidate_send_stun_bind_request(tnet_ice_candidate_t* self, const struct sockaddr_storage* server_addr, const char* username, const char* password)
+{
+ tnet_stun_pkt_t *request = tsk_null;
+ tsk_buffer_t *buffer = tsk_null;
+ int ret, sendBytes;
+
+ if (!self || !server_addr || !TNET_SOCKET_IS_VALID(self->socket)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ request = _tnet_ice_candidate_stun_create_bind_request(self, username, password);
+ if (!request){
+ TSK_DEBUG_ERROR("Failed to create STUN request");
+ ret = -2;
+ goto bail;
+ }
+
+ if ((ret = tnet_stun_pkt_write_with_padding_2(request, &buffer))){
+ TSK_DEBUG_ERROR("Failed to serialize STUN request");
+ goto bail;
+ }
+
+ sendBytes = tnet_sockfd_sendto(self->socket->fd, (const struct sockaddr*)server_addr, buffer->data, buffer->size);// return number of sent bytes
+ if (sendBytes == buffer->size){
+ memcpy(self->stun.transac_id, request->transac_id, sizeof(tnet_stun_transac_id_t));
+ ret = 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Only %d bytes sent", sendBytes);
+ ret = -4;
+ goto bail;
+ }
+
+bail:
+ TSK_OBJECT_SAFE_FREE(request);
+ TSK_OBJECT_SAFE_FREE(buffer);
+
+ return 0;
+}
+
+int tnet_ice_candidate_process_stun_response(tnet_ice_candidate_t* self, const tnet_stun_pkt_resp_t* response, tnet_fd_t fd)
+{
+ int ret = 0;
+
+ if (!self || !response){
+ TSK_DEBUG_ERROR("Inavlid parameter");
+ return -1;
+ }
+
+ //if(!(_tnet_ice_candidate_stun_transac_id_equals(response->transac_id, self->stun.transac_id))){
+ // TSK_DEBUG_ERROR("Transaction id mismatch");
+ // return -2;
+ //}
+
+ if (TNET_STUN_PKT_RESP_IS_ERROR(response)) {
+ uint16_t u_code;
+ if ((ret = tnet_stun_pkt_get_errorcode(response, &u_code))) {
+ return ret;
+ }
+ if (u_code == kStunErrCodeUnauthorized || u_code == kStunErrCodeStaleNonce) {
+ const tnet_stun_attr_vdata_t* pc_attr;
+ if (u_code == kStunErrCodeUnauthorized) {
+ // Make sure this is not an authentication failure (#2 401)
+ // Do not send another req to avoid endless messages
+ if ((tnet_stun_pkt_attr_exists(response, tnet_stun_attr_type_message_integrity))) { // already has a MESSAGE-INTEGRITY?
+ TSK_DEBUG_ERROR("TURN authentication failed");
+ return -3;
+ }
+ }
+ if ((ret = tnet_stun_pkt_attr_find_first(response, tnet_stun_attr_type_nonce, (const tnet_stun_attr_t**)&pc_attr)) == 0 && pc_attr) {
+ tsk_strupdate(&self->stun.nonce, pc_attr->p_data_ptr);
+ }
+ if ((ret = tnet_stun_pkt_attr_find_first(response, tnet_stun_attr_type_realm, (const tnet_stun_attr_t**)&pc_attr)) == 0 && pc_attr) {
+ tsk_strupdate(&self->stun.realm, pc_attr->p_data_ptr);
+ }
+ return 0;
+ }
+ else {
+ TSK_DEBUG_ERROR("STUN error: %hu", u_code);
+ return -4;
+ }
+ }
+ else if (TNET_STUN_PKT_RESP_IS_SUCCESS(response)) {
+ const tnet_stun_attr_address_t* pc_attr_addr;
+ if (((ret = tnet_stun_pkt_attr_find_first(response, tnet_stun_attr_type_xor_mapped_address, (const tnet_stun_attr_t**)&pc_attr_addr)) == 0 && pc_attr_addr)
+ || ((ret = tnet_stun_pkt_attr_find_first(response, tnet_stun_attr_type_mapped_address, (const tnet_stun_attr_t**)&pc_attr_addr)) == 0 && pc_attr_addr)) {
+ tnet_ip_t ip;
+ if ((ret = tnet_stun_utils_inet_ntop((pc_attr_addr->e_family == tnet_stun_address_family_ipv6), &pc_attr_addr->address, &ip))) {
+ return ret;
+ }
+ tsk_strupdate(&self->stun.srflx_addr, ip);
+ self->stun.srflx_port = pc_attr_addr->u_port;
+ }
+ }
+
+ return ret;
+}
+
+const tnet_ice_candidate_t* tnet_ice_candidate_find_by_fd(tnet_ice_candidates_L_t* candidates, tnet_fd_t fd)
+{
+ if (candidates) {
+ const tsk_list_item_t *item;
+ const tnet_ice_candidate_t* candidate;
+
+ tsk_list_lock(candidates);
+ tsk_list_foreach(item, candidates) {
+ if (!(candidate = item->data)) {
+ continue;
+ }
+ if (candidate->socket && (candidate->socket->fd == fd)) {
+ tsk_list_unlock(candidates);
+ return candidate;
+ }
+ }
+ }
+
+ return tsk_null;
+}
+
+const char* tnet_ice_candidate_get_ufrag(const tnet_ice_candidate_t* self)
+{
+ if (self){
+ return self->ufrag ? self->ufrag : tnet_ice_candidate_get_att_value(self, "username");
+ }
+ return tsk_null;
+}
+
+const char* tnet_ice_candidate_get_pwd(const tnet_ice_candidate_t* self)
+{
+ if (self){
+ return self->pwd ? self->pwd : tnet_ice_candidate_get_att_value(self, "password");
+ }
+ return tsk_null;
+}
+
+static int _tnet_ice_candidate_tostring(
+ uint8_t* foundation,
+ uint32_t comp_id,
+ const char* transport_str,
+ uint32_t priority,
+ const char* connection_addr,
+ tnet_port_t port,
+ const char* cand_type_str,
+ const tsk_params_L_t *extension_att_list,
+ char** output)
+{
+ if (!output) {
+ TSK_DEBUG_ERROR("Invalid argument");
+ return -1;
+ }
+ tsk_sprintf(output, "%s %d %s %d %s %d typ %s",
+ foundation,
+ comp_id,
+ transport_str,
+ priority,
+ connection_addr,
+ port,
+ cand_type_str);
+
+ if (extension_att_list) {
+ const tsk_list_item_t *item;
+ tsk_list_foreach(item, extension_att_list){
+ tsk_strcat_2(output, " %s %s", TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value);
+ }
+ }
+ return 0;
+}
+
+static const char* _tnet_ice_candidate_get_foundation(tnet_ice_cand_type_t type)
+{
+ switch (type){
+ case tnet_ice_cand_type_host: return TNET_ICE_CANDIDATE_FOUNDATION_HOST;
+ case tnet_ice_cand_type_srflx: return TNET_ICE_CANDIDATE_FOUNDATION_SRFLX;
+ case tnet_ice_cand_type_prflx: return TNET_ICE_CANDIDATE_FOUNDATION_PRFLX;
+ case tnet_ice_cand_type_relay: default: return TNET_ICE_CANDIDATE_FOUNDATION_RELAY;
+ }
+}
+
+
+static tsk_bool_t _tnet_ice_candidate_stun_transac_id_equals(const tnet_stun_transac_id_t id1, const tnet_stun_transac_id_t id2)
+{
+ tsk_size_t i;
+ static const tsk_size_t size = sizeof(tnet_stun_transac_id_t);
+ for (i = 0; i < size; i++){
+ if (id1[i] != id2[i]){
+ return tsk_false;
+ }
+ }
+ return tsk_true;
+}
+
+static tnet_stun_pkt_t * _tnet_ice_candidate_stun_create_bind_request(tnet_ice_candidate_t* self, const char* username, const char* password)
+{
+ tnet_stun_pkt_t *request = tsk_null;
+ int ret;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_binding_request, &request))) {
+ TSK_DEBUG_ERROR("Failed to create STUN Bind request");
+ goto bail;
+ }
+ // add attributes
+ request->opt.dontfrag = 0;
+ ret = tnet_stun_pkt_attrs_add(request,
+ TNET_STUN_PKT_ATTR_ADD_SOFTWARE_ZT(kStunSoftware),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ if (username && self->stun.realm && self->stun.nonce) {
+ if ((ret = tnet_stun_pkt_auth_prepare(request, username, password, self->stun.realm, self->stun.nonce))) {
+ goto bail;
+ }
+ }
+
+bail:
+ if (ret) {
+ TSK_OBJECT_SAFE_FREE(request);
+ }
+ return request;
+}
+
+static const char* _tnet_ice_candidate_get_transport_str(tnet_socket_type_t transport_e)
+{
+#define TRANSPORT_GET(STR) \
+if(TNET_SOCKET_TYPE_IS_##STR(transport_e)){ \
+return TNET_ICE_CANDIDATE_TRANSPORT_##STR; \
+}
+ TRANSPORT_GET(UDP);
+ TRANSPORT_GET(TCP);
+ TRANSPORT_GET(TLS);
+ TRANSPORT_GET(SCTP);
+ TRANSPORT_GET(WS);
+ TRANSPORT_GET(WSS);
+ return "UNKNOWN";
+
+#undef TRANSPORT_GET
+}
+
+static tnet_socket_type_t _tnet_ice_candidate_get_transport_type(tsk_bool_t ipv6, const char* transport_str)
+{
+#define TRANSPORT_GET(STR, str) \
+if(tsk_striequals(TNET_ICE_CANDIDATE_TRANSPORT_##STR, transport_str)){ \
+return tnet_socket_type_##str##_ipv4; \
+}
+
+ TRANSPORT_GET(UDP, udp);
+ TRANSPORT_GET(TCP, tcp);
+ TRANSPORT_GET(TLS, tls);
+ TRANSPORT_GET(SCTP, sctp);
+ TRANSPORT_GET(WS, ws);
+ TRANSPORT_GET(WSS, wss);
+ return tnet_socket_type_invalid;
+
+#undef TRANSPORT_GET
+}
+
+static const char* _tnet_ice_candidate_get_candtype_str(tnet_ice_cand_type_t candtype_e)
+{
+ switch (candtype_e){
+ case tnet_ice_cand_type_unknown:
+ default: return "unknown";
+ case tnet_ice_cand_type_host: return TNET_ICE_CANDIDATE_TYPE_HOST;
+ case tnet_ice_cand_type_srflx: return TNET_ICE_CANDIDATE_TYPE_SRFLX;
+ case tnet_ice_cand_type_prflx: return TNET_ICE_CANDIDATE_TYPE_PRFLX;
+ case tnet_ice_cand_type_relay: return TNET_ICE_CANDIDATE_TYPE_RELAY;
+ }
+}
+
+static tnet_ice_cand_type_t _tnet_ice_candtype_get_transport_type(const char* candtype_str)
+{
+ if (tsk_striequals(TNET_ICE_CANDIDATE_TYPE_HOST, candtype_str)){
+ return tnet_ice_cand_type_host;
+ }
+ else if (tsk_striequals(TNET_ICE_CANDIDATE_TYPE_SRFLX, candtype_str)){
+ return tnet_ice_cand_type_srflx;
+ }
+ else if (tsk_striequals(TNET_ICE_CANDIDATE_TYPE_PRFLX, candtype_str)){
+ return tnet_ice_cand_type_prflx;
+ }
+ else if (tsk_striequals(TNET_ICE_CANDIDATE_TYPE_RELAY, candtype_str)){
+ return tnet_ice_cand_type_relay;
+ }
+ else{
+ return tnet_ice_cand_type_unknown;
+ }
+}
diff --git a/tinyNET/src/ice/tnet_ice_candidate.h b/tinyNET/src/ice/tnet_ice_candidate.h
new file mode 100644
index 0000000..d2cb126
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice_candidate.h
@@ -0,0 +1,130 @@
+/*
+* Copyright (C) 2012-2014 Mamadou DIOP
+* Copyright (C) 2012-2014 Doubango Telecom <http://www.doubango.org>.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+#ifndef TNET_ICE_CANDIDATE_H
+#define TNET_ICE_CANDIDATE_H
+
+#include "tinynet_config.h"
+
+#include "stun/tnet_stun_pkt.h"
+#include "stun/tnet_stun_attr.h"
+#include "stun/tnet_stun_utils.h"
+#include "tnet_socket.h"
+
+#include "tsk_params.h"
+
+TNET_BEGIN_DECLS
+
+#define TNET_ICE_CANDIDATE_TRANSPORT_UDP "udp"
+#define TNET_ICE_CANDIDATE_TRANSPORT_TCP "tcp"
+#define TNET_ICE_CANDIDATE_TRANSPORT_TLS "tls"
+#define TNET_ICE_CANDIDATE_TRANSPORT_SCTP "sctp"
+#define TNET_ICE_CANDIDATE_TRANSPORT_WS "ws"
+#define TNET_ICE_CANDIDATE_TRANSPORT_WSS "wss"
+
+#define TNET_ICE_CANDIDATE_TYPE_HOST "host"
+#define TNET_ICE_CANDIDATE_TYPE_SRFLX "srflx"
+#define TNET_ICE_CANDIDATE_TYPE_PRFLX "prflx"
+#define TNET_ICE_CANDIDATE_TYPE_RELAY "relay"
+
+#define TNET_ICE_CANDIDATE_PREF_HOST 126
+#define TNET_ICE_CANDIDATE_PREF_SRFLX 100
+#define TNET_ICE_CANDIDATE_PREF_PRFLX 110
+#define TNET_ICE_CANDIDATE_PREF_RELAY 0
+
+#define TNET_ICE_CANDIDATE_FOUNDATION_HOST "fhost"
+#define TNET_ICE_CANDIDATE_FOUNDATION_SRFLX "fsrflx"
+#define TNET_ICE_CANDIDATE_FOUNDATION_PRFLX "fprflx"
+#define TNET_ICE_CANDIDATE_FOUNDATION_RELAY "frelay"
+
+#define TNET_ICE_CANDIDATE_COMPID_RTP 1
+#define TNET_ICE_CANDIDATE_COMPID_RTCP 2
+
+#define TNET_ICE_CANDIDATE_FOUND_SIZE_PREF 15
+
+typedef enum tnet_ice_cand_type_e
+{
+ tnet_ice_cand_type_unknown,
+ tnet_ice_cand_type_host,
+ tnet_ice_cand_type_srflx,
+ tnet_ice_cand_type_prflx,
+ tnet_ice_cand_type_relay
+}
+tnet_ice_cand_type_t;
+
+typedef struct tnet_ice_candidate_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_ice_cand_type_t type_e;
+ uint8_t foundation[33]; // 1*32ice-char
+ uint32_t comp_id; // 1*5DIGIT
+ char* transport_str; // "UP" / token
+ enum tnet_socket_type_e transport_e;
+ uint32_t priority; // 1*10DIGIST [1 - (2**31 - 1)]
+ char* cand_type_str; // "host" / "srflx" / "prflx" / "relay" / "token"
+ tnet_ip_t connection_addr;
+ tnet_port_t port;
+ tsk_params_L_t *extension_att_list;
+
+ tsk_bool_t is_ice_jingle;
+ tsk_bool_t is_rtp;
+ tsk_bool_t is_video;
+ uint16_t local_pref; // [0 - 65535]
+
+ char* ufrag;
+ char* pwd;
+
+ struct tnet_socket_s* socket;
+ struct{
+ char* nonce;
+ char* realm;
+ char* srflx_addr;
+ tnet_stun_transac_id_t transac_id;
+ tnet_port_t srflx_port;
+ } stun;
+ struct {
+ struct tnet_turn_session_s* ss;
+ char* relay_addr;
+ tnet_port_t relay_port;
+ } turn;
+
+ char *tostring;
+}
+tnet_ice_candidate_t;
+
+typedef tsk_list_t tnet_ice_candidates_L_t;
+
+tnet_ice_candidate_t* tnet_ice_candidate_create(tnet_ice_cand_type_t type_e, struct tnet_socket_s* socket, tsk_bool_t is_ice_jingle, tsk_bool_t is_rtp, tsk_bool_t is_video, const char* ufrag, const char* pwd, const char *foundation);
+TINYNET_API tnet_ice_candidate_t* tnet_ice_candidate_parse(const char* str);
+int tnet_ice_candidate_set_credential(tnet_ice_candidate_t* self, const char* ufrag, const char* pwd);
+int tnet_ice_candidate_set_rflx_addr(tnet_ice_candidate_t* self, const char* addr, tnet_port_t port);
+TINYNET_API const char* tnet_ice_candidate_get_att_value(const tnet_ice_candidate_t* self, const char* att_name);
+int tnet_ice_candidate_set_local_pref(tnet_ice_candidate_t* self, uint16_t local_pref);
+TINYNET_API const char* tnet_ice_candidate_tostring(tnet_ice_candidate_t* self);
+int tnet_ice_candidate_send_stun_bind_request(tnet_ice_candidate_t* self, const struct sockaddr_storage* server_addr, const char* username, const char* password);
+int tnet_ice_candidate_process_stun_response(tnet_ice_candidate_t* self, const tnet_stun_pkt_resp_t* response, tnet_fd_t fd);
+const tnet_ice_candidate_t* tnet_ice_candidate_find_by_fd(tnet_ice_candidates_L_t* candidates, tnet_fd_t fd);
+const char* tnet_ice_candidate_get_ufrag(const tnet_ice_candidate_t* self);
+const char* tnet_ice_candidate_get_pwd(const tnet_ice_candidate_t* self);
+
+TNET_END_DECLS
+
+#endif /* TNET_ICE_CANDIDATE_H */
diff --git a/tinyNET/src/ice/tnet_ice_ctx.c b/tinyNET/src/ice/tnet_ice_ctx.c
new file mode 100644
index 0000000..94d3042
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice_ctx.c
@@ -0,0 +1,2883 @@
+/*
+ * Copyright (C) 2012-2015 Mamadou DIOP
+ * Copyright (C) 2012-2015 Doubango Telecom <http://www.doubango.org>.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+
+/**@file tnet_ice_ctx.c
+ * @brief Interactive Connectivity Establishment (ICE) implementation as per RFC 5245
+ *
+ */
+#include "tnet_ice_ctx.h"
+#include "tnet_ice_event.h"
+#include "tnet_ice_candidate.h"
+#include "tnet_ice_pair.h"
+#include "tnet_ice_utils.h"
+#include "tnet_utils.h"
+#include "tnet_endianness.h"
+#include "tnet_transport.h"
+#include "tnet_proxydetect.h"
+
+#include "stun/tnet_stun.h"
+#include "stun/tnet_stun_message.h"
+#include "stun/tnet_stun_types.h"
+#include "turn/tnet_turn_session.h"
+
+#include "tsk_condwait.h"
+#include "tsk_time.h"
+#include "tsk_timer.h"
+#include "tsk_runnable.h"
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_fsm.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef LONG_MAX
+# define LONG_MAX 2147483647L
+#endif
+
+#if !defined(TNET_ICE_DEBUG_STATE_MACHINE)
+# define TNET_ICE_DEBUG_STATE_MACHINE 1
+#endif
+
+/**@ingroup tnet_nat_group
+ * Estimate of the round-trip time (RTT) in millisecond.
+ */
+#define kIceDefaultRTO 500
+/**@ingroup tnet_nat_group
+ * Number of retransmission for UDP retransmission in millisecond.
+ * 7.2.1. Sending over UDP
+ Rc SHOULD be configurable and SHOULD have a default of 7.
+ */
+#define kIceDefaultRC 4 //7
+
+#define kIceDefaultTurnEnabled 0 // Relay candidates
+#define kIceDefaultStunEnabled 1 // Reflexive candidates
+
+#define kIceCandidatesCountMax 40
+#define kIceServersCountMax 10
+
+#define kIceConnCheckMinTriesMin 0
+#define kIceConnCheckMinTriesMax 3
+
+#define kIcePairsBuildingTimeMax 2500 // maximum time to build pairs
+
+typedef tsk_list_t tnet_ice_servers_L_t;
+
+static const char* foundation_default = tsk_null;
+
+typedef enum tnet_ice_server_proto_e
+{
+ tnet_ice_server_proto_none = 0x00,
+ tnet_ice_server_proto_stun = (0x01 << 0),
+ tnet_ice_server_proto_turn = (0x01 << 1),
+ tnet_ice_server_proto_all = 0xFF
+}
+tnet_ice_server_proto_t;
+
+static int _tnet_ice_ctx_fsm_act(struct tnet_ice_ctx_s* self, tsk_fsm_action_id action_id);
+static int _tnet_ice_ctx_signal_async(struct tnet_ice_ctx_s* self, tnet_ice_event_type_t type, const char* phrase);
+static int _tnet_ice_ctx_cancel(struct tnet_ice_ctx_s* self, tsk_bool_t silent);
+static int _tnet_ice_ctx_restart(struct tnet_ice_ctx_s* self);
+static int _tnet_ice_ctx_recv_stun_message_for_pair(struct tnet_ice_ctx_s* self, const struct tnet_ice_pair_s* pair, const void* data, tsk_size_t size, tnet_fd_t local_fd, const struct sockaddr_storage* remote_addr, tsk_bool_t *role_conflict);
+static int _tnet_ice_ctx_send_turn_raw(struct tnet_ice_ctx_s* self, struct tnet_turn_session_s* turn_ss, tnet_turn_peer_id_t turn_peer_id, const void* data, tsk_size_t size);
+static int _tnet_ice_ctx_build_pairs(struct tnet_ice_ctx_s* self, tnet_ice_candidates_L_t* local_candidates, tnet_ice_candidates_L_t* remote_candidates, tnet_ice_pairs_L_t* result_pairs, tsk_bool_t is_controlling, uint64_t tie_breaker, tsk_bool_t is_ice_jingle, tsk_bool_t is_rtcpmuxed);
+static void* TSK_STDCALL _tnet_ice_ctx_run(void* self);
+
+static int _tnet_ice_ctx_fsm_Started_2_GatheringHostCandidates_X_GatherHostCandidates(va_list *app);
+static int _tnet_ice_ctx_fsm_GatheringHostCandidates_2_GatheringHostCandidatesDone_X_Success(va_list *app);
+static int _tnet_ice_ctx_fsm_GatheringHostCandidates_2_Terminated_X_Failure(va_list *app);
+static int _tnet_ice_ctx_fsm_GatheringHostCandidatesDone_2_GatheringReflexiveCandidates_X_GatherReflexiveCandidates(va_list *app);
+static int _tnet_ice_ctx_fsm_GatheringReflexiveCandidates_2_GatheringReflexiveCandidatesDone_X_Success(va_list *app);
+static int _tnet_ice_ctx_fsm_GatheringReflexiveCandidates_2_Terminated_X_Failure(va_list *app);
+static int _tnet_ice_ctx_fsm_GatheringReflexiveCandidatesDone_2_GatheringRelayCandidates_X_GatherRelayCandidates(va_list *app);
+static int _tnet_ice_ctx_fsm_GatheringRelayCandidates_2_GatheringRelayCandidatesDone_X_Success(va_list *app);
+static int _tnet_ice_ctx_fsm_GatheringRelayCandidates_2_Terminated_X_Failure(va_list *app);
+static int _tnet_ice_ctx_fsm_Any_2_GatheringCompleted_X_GatheringComplet(va_list *app);
+static int _tnet_ice_ctx_fsm_Any_2_Started_X_Cancel(va_list *app);
+static int _tnet_ice_ctx_fsm_GatheringCompleted_2_ConnChecking_X_ConnCheck(va_list *app);
+static int _tnet_ice_ctx_fsm_ConnChecking_2_ConnCheckingCompleted_X_Success(va_list *app);
+static int _tnet_ice_ctx_fsm_ConnChecking_2_Terminated_X_Failure(va_list *app);
+static int _tnet_ice_ctx_fsm_Any_2_Terminated_X_AnyNotStarted(va_list *app); // Any action if not started
+
+static int _tnet_ice_ctx_servers_clear(struct tnet_ice_ctx_s* self);
+static int _tnet_ice_ctx_server_add(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto,
+ enum tnet_socket_type_e e_transport,
+ const char* str_server_addr, uint16_t u_server_port,
+ const char* str_software,
+ const char* str_username, const char* str_password);
+static int _tnet_ice_ctx_server_remove(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto, enum tnet_socket_type_e e_transport, const char* str_server_addr, uint16_t u_server_port);
+static const struct tnet_ice_server_s* _tnet_ice_ctx_server_find(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto, enum tnet_socket_type_e e_transport, const char* str_server_addr, uint16_t u_server_port);
+static tsk_bool_t _tnet_ice_ctx_server_exists(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto, enum tnet_socket_type_e e_transport, const char* str_server_addr, uint16_t u_server_port);
+static tsk_size_t _tnet_ice_ctx_servers_count_by_proto(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto);
+static tnet_ice_servers_L_t* _tnet_ice_ctx_servers_copy(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto);
+
+static int _tnet_ice_ctx_fsm_OnTerminated(struct tnet_ice_ctx_s* self);
+static tsk_bool_t _tnet_ice_ctx_fsm_cond_NotStarted(struct tnet_ice_ctx_s* self, const void* _any);
+static int _tnet_ice_ctx_turn_callback(const struct tnet_turn_session_event_xs *e);
+
+typedef struct tnet_ice_server_s
+{
+ TSK_DECLARE_OBJECT;
+
+ enum tnet_socket_type_e e_transport;
+ tnet_ice_server_proto_t e_proto;
+ char* str_server_addr;
+ uint16_t u_server_port;
+ struct sockaddr_storage obj_server_addr;
+ char* str_software;
+ char* str_username;
+ char* str_password;
+ int rto;
+}
+tnet_ice_server_t;
+
+static tsk_object_t* tnet_ice_server_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_ice_server_t *ice_server = self;
+ if (ice_server) {
+ }
+ return self;
+}
+static tsk_object_t* tnet_ice_server_dtor(tsk_object_t * self)
+{
+ tnet_ice_server_t *ice_server = self;
+ if (ice_server) {
+ TSK_FREE(ice_server->str_server_addr);
+ TSK_FREE(ice_server->str_software);
+ TSK_FREE(ice_server->str_username);
+ TSK_FREE(ice_server->str_password);
+
+ TSK_DEBUG_INFO("*** ICE server destroyed ***");
+ }
+ return self;
+}
+static const tsk_object_def_t tnet_ice_server_def_s =
+{
+ sizeof(tnet_ice_server_t),
+ tnet_ice_server_ctor,
+ tnet_ice_server_dtor,
+ tsk_null,
+};
+
+static tnet_ice_server_t* tnet_ice_server_create(
+ enum tnet_ice_server_proto_e e_proto,
+ enum tnet_socket_type_e e_transport,
+ const char* str_server_addr, uint16_t u_server_port,
+ const char* str_software,
+ const char* str_username, const char* str_password)
+{
+ tnet_ice_server_t *ice_server;
+ struct sockaddr_storage obj_server_addr;
+
+ if (tsk_strnullORempty(str_server_addr) || !u_server_port) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ if (tnet_sockaddr_init(str_server_addr, u_server_port, e_transport, &obj_server_addr) != 0) {
+ TSK_DEBUG_ERROR("Invalid server address (host=%s, port=%d, transport=%d)", str_server_addr, u_server_port, e_transport);
+ return tsk_null;
+ }
+
+ if ((ice_server = tsk_object_new(&tnet_ice_server_def_s))) {
+ ice_server->e_proto = e_proto;
+ ice_server->e_transport = e_transport;
+ tsk_strupdate(&ice_server->str_server_addr, str_server_addr);
+ ice_server->u_server_port = u_server_port;
+ tsk_strupdate(&ice_server->str_software, str_software);
+ tsk_strupdate(&ice_server->str_username, str_username);
+ tsk_strupdate(&ice_server->str_password, str_password);
+ memcpy(&ice_server->obj_server_addr, &obj_server_addr, sizeof(struct sockaddr_storage));
+ }
+ return ice_server;
+}
+
+typedef struct tnet_ice_ctx_s
+{
+ TSK_DECLARE_RUNNABLE;
+
+ tsk_bool_t is_started;
+ tsk_bool_t is_active;
+ tsk_bool_t is_sync_mode;
+ tsk_bool_t is_silent_mode;
+ tnet_ice_callback_f callback;
+ const void* userdata;
+ tsk_bool_t use_ipv6;
+ tsk_bool_t use_rtcp;
+ tsk_bool_t use_rtcpmux;
+ tsk_bool_t is_video;
+ tsk_bool_t is_building_pairs;
+ tsk_bool_t unicast;
+ tsk_bool_t anycast;
+ tsk_bool_t multicast;
+
+ tsk_bool_t is_connchecking;
+ tsk_bool_t is_controlling;
+ tsk_bool_t is_ice_jingle;
+ tsk_bool_t is_turn_enabled;
+ tsk_bool_t is_stun_enabled;
+ uint64_t tie_breaker;
+ uint64_t concheck_timeout;
+
+ const void* rtp_callback_data;
+ tnet_ice_rtp_callback_f rtp_callback;
+
+ tnet_ice_servers_L_t *servers;
+
+ char* ufrag;
+ char* pwd;
+
+ tsk_timer_manager_handle_t* h_timer_mgr;
+
+ tsk_fsm_t* fsm;
+
+ tsk_condwait_handle_t* condwait_pairs;
+ tnet_ice_candidates_L_t* candidates_local;
+ tnet_ice_candidates_L_t* candidates_remote;
+ tnet_ice_pairs_L_t* candidates_pairs;
+ tsk_bool_t have_nominated_offer;
+ tsk_bool_t have_nominated_answer;
+ tsk_bool_t have_nominated_symetric; /**< Whether symetic RTP has been negotiated */
+
+ uint16_t RTO; /**< Estimate of the round-trip time (RTT) in millisecond */
+ uint16_t Rc; /**< Number of retransmissions for UDP in millisecond */
+
+ struct {
+ char* path_priv;
+ char* path_pub;
+ char* path_ca;
+ tsk_bool_t verify;
+ } ssl;
+
+ struct {
+ tsk_bool_t auto_detect;
+ struct tnet_proxyinfo_s* info;
+ }
+ proxy;
+
+ struct {
+ tsk_condwait_handle_t* condwait;
+ struct tnet_turn_session_s* ss_nominated_rtp;
+ tnet_turn_peer_id_t peer_id_rtp;
+ struct tnet_turn_session_s* ss_nominated_rtcp;
+ tnet_turn_peer_id_t peer_id_rtcp;
+ } turn;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_ice_ctx_t;
+
+typedef struct tnet_ice_action_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_fsm_action_id id;
+}
+tnet_ice_action_t;
+
+typedef enum _fsm_state_e
+{
+ _fsm_state_Started,
+ _fsm_state_GatheringHostCandidates,
+ _fsm_state_GatheringHostCandidatesDone,
+ _fsm_state_GatheringReflexiveCandidates,
+ _fsm_state_GatheringReflexiveCandidatesDone,
+ _fsm_state_GatheringRelayCandidates,
+ _fsm_state_GatheringRelayCandidatesDone,
+ _fsm_state_GatheringCompleted,
+ _fsm_state_ConnChecking,
+ _fsm_state_ConnCheckingCompleted,
+ _fsm_state_Terminated
+}
+_fsm_state_t;
+
+typedef enum _fsm_action_e
+{
+ _fsm_action_Success,
+ _fsm_action_Failure,
+ _fsm_action_GatherHostCandidates,
+ _fsm_action_GatherReflexiveCandidates,
+ _fsm_action_GatherRelayCandidates,
+ _fsm_action_GatheringComplet,
+ _fsm_action_ConnCheck,
+ _fsm_action_Cancel,
+ _fsm_action_Error,
+}
+_fsm_action_t;
+
+static tsk_object_t* tnet_ice_action_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_ice_action_t *action = self;
+ if (action){
+ }
+ return self;
+}
+static tsk_object_t* tnet_ice_action_dtor(tsk_object_t * self)
+{
+ tnet_ice_action_t *action = self;
+ if (action){
+ }
+ return self;
+}
+static const tsk_object_def_t tnet_ice_action_def_s =
+{
+ sizeof(tnet_ice_action_t),
+ tnet_ice_action_ctor,
+ tnet_ice_action_dtor,
+ tsk_null,
+};
+static tnet_ice_action_t* tnet_ice_action_create(tsk_fsm_action_id id)
+{
+ tnet_ice_action_t *action = tsk_object_new(&tnet_ice_action_def_s);
+ if (action){
+ action->id = id;
+ }
+ return action;
+}
+
+
+
+
+static tsk_object_t* tnet_ice_ctx_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_ice_ctx_t *ctx = self;
+ if (ctx){
+ tsk_safeobj_init(ctx);
+
+ if (!(ctx->h_timer_mgr = tsk_timer_manager_create())){
+ TSK_DEBUG_ERROR("Failed to create timer manager");
+ return tsk_null;
+ }
+ if (!(ctx->fsm = tsk_fsm_create(_fsm_state_Started, _fsm_state_Terminated))){
+ TSK_DEBUG_ERROR("Failed to create state machine");
+ return tsk_null;
+ }
+ if (!(ctx->candidates_local = tsk_list_create())){
+ TSK_DEBUG_ERROR("Failed to create candidates list");
+ return tsk_null;
+ }
+ if (!(ctx->candidates_remote = tsk_list_create())){
+ TSK_DEBUG_ERROR("Failed to create candidates list");
+ return tsk_null;
+ }
+ if (!(ctx->candidates_pairs = tsk_list_create())){
+ TSK_DEBUG_ERROR("Failed to create candidates list");
+ return tsk_null;
+ }
+
+ // Create condwait for pairs
+ if (!(ctx->condwait_pairs = tsk_condwait_create())) {
+ TSK_DEBUG_ERROR("Failed to create condwait for pairs");
+ return tsk_null;
+ }
+
+ // Create list objects to hold the servers
+ if (!(ctx->servers = tsk_list_create())){
+ TSK_DEBUG_ERROR("Failed to create server list");
+ return tsk_null;
+ }
+
+ tsk_runnable_set_important(TSK_RUNNABLE(self), tsk_false);
+
+ /* 7.2.1. Sending over UDP
+ In fixed-line access links, a value of 500 ms is RECOMMENDED.
+ */
+ ctx->RTO = kIceDefaultRTO;
+
+ /* 7.2.1. Sending over UDP
+ Rc SHOULD be configurable and SHOULD have a default of 7.
+ */
+ ctx->Rc = kIceDefaultRC;
+
+ ctx->tie_breaker = ((tsk_time_now() << 32) ^ tsk_time_now());
+ ctx->is_ice_jingle = tsk_false;
+ ctx->is_stun_enabled = kIceDefaultStunEnabled;
+ ctx->is_turn_enabled = kIceDefaultTurnEnabled;
+
+ ctx->concheck_timeout = LONG_MAX;
+ }
+ return self;
+}
+static tsk_object_t* tnet_ice_ctx_dtor(tsk_object_t * self)
+{
+ tnet_ice_ctx_t *ctx = self;
+ if (ctx){
+ tnet_ice_ctx_stop(ctx);
+ if (ctx->h_timer_mgr){
+ tsk_timer_manager_destroy(&ctx->h_timer_mgr);
+ }
+
+ TSK_OBJECT_SAFE_FREE(ctx->fsm);
+ TSK_OBJECT_SAFE_FREE(ctx->candidates_local);
+ TSK_OBJECT_SAFE_FREE(ctx->candidates_remote);
+ TSK_OBJECT_SAFE_FREE(ctx->candidates_pairs);
+
+ TSK_OBJECT_SAFE_FREE(ctx->turn.ss_nominated_rtp);
+ TSK_OBJECT_SAFE_FREE(ctx->turn.ss_nominated_rtcp);
+ if (ctx->turn.condwait) {
+ tsk_condwait_destroy(&ctx->turn.condwait);
+ }
+ if (ctx->condwait_pairs) {
+ tsk_condwait_destroy(&ctx->condwait_pairs);
+ }
+ TSK_OBJECT_SAFE_FREE(ctx->servers);
+
+ TSK_OBJECT_SAFE_FREE(ctx->proxy.info);
+
+ TSK_FREE(ctx->ssl.path_priv);
+ TSK_FREE(ctx->ssl.path_pub);
+ TSK_FREE(ctx->ssl.path_ca);
+
+ tsk_safeobj_deinit(ctx);
+ }
+ TSK_DEBUG_INFO("*** ICE context destroyed ***");
+ return self;
+}
+static const tsk_object_def_t tnet_ice_ctx_def_s =
+{
+ sizeof(tnet_ice_ctx_t),
+ tnet_ice_ctx_ctor,
+ tnet_ice_ctx_dtor,
+ tsk_null,
+};
+
+
+tnet_ice_ctx_t* tnet_ice_ctx_create(tsk_bool_t is_ice_jingle, tsk_bool_t use_ipv6, tsk_bool_t use_rtcp, tsk_bool_t is_video, tnet_ice_callback_f callback, const void* userdata)
+{
+ tnet_ice_ctx_t* ctx;
+
+ if (!(ctx = tsk_object_new(&tnet_ice_ctx_def_s))){
+ TSK_DEBUG_ERROR("Failed to create ICE context object");
+ return tsk_null;
+ }
+
+ ctx->is_ice_jingle = is_ice_jingle;
+ ctx->use_ipv6 = use_ipv6;
+ ctx->use_rtcp = use_rtcp;
+ ctx->is_video = is_video;
+ ctx->callback = callback;
+ ctx->userdata = userdata;
+ ctx->unicast = tsk_true;
+ ctx->anycast = tsk_false;
+ ctx->multicast = tsk_false;
+
+ tnet_ice_utils_set_ufrag(&ctx->ufrag);
+ tnet_ice_utils_set_pwd(&ctx->pwd);
+
+ ctx->fsm->debug = TNET_ICE_DEBUG_STATE_MACHINE;
+ tsk_fsm_set_callback_terminated(ctx->fsm, TSK_FSM_ONTERMINATED_F(_tnet_ice_ctx_fsm_OnTerminated), (const void*)ctx);
+ tsk_fsm_set(ctx->fsm,
+ // (Started) -> (GatherHostCandidates) -> (GatheringHostCandidates)
+ TSK_FSM_ADD_ALWAYS(_fsm_state_Started, _fsm_action_GatherHostCandidates, _fsm_state_GatheringHostCandidates, _tnet_ice_ctx_fsm_Started_2_GatheringHostCandidates_X_GatherHostCandidates, "ICE_Started_2_GatheringHostCandidates_X_GatherHostCandidates"),
+ // (GatheringHostCandidates) -> (Success) -> (GatheringHostCandidatesDone)
+ TSK_FSM_ADD_ALWAYS(_fsm_state_GatheringHostCandidates, _fsm_action_Success, _fsm_state_GatheringHostCandidatesDone, _tnet_ice_ctx_fsm_GatheringHostCandidates_2_GatheringHostCandidatesDone_X_Success, "ICE_GatheringHostCandidates_2_GatheringHostCandidatesDone_X_Success"),
+ // (GatheringHostCandidates) -> (Failure) -> (Terminated)
+ TSK_FSM_ADD_ALWAYS(_fsm_state_GatheringHostCandidates, _fsm_action_Failure, _fsm_state_Terminated, _tnet_ice_ctx_fsm_GatheringHostCandidates_2_Terminated_X_Failure, "ICE_GatheringHostCandidates_2_Terminated_X_Failure"),
+
+ // (GatheringHostCandidatesDone) -> (GatherReflexiveCandidates) -> (GatheringReflexiveCandidates)
+ TSK_FSM_ADD_ALWAYS(_fsm_state_GatheringHostCandidatesDone, _fsm_action_GatherReflexiveCandidates, _fsm_state_GatheringReflexiveCandidates, _tnet_ice_ctx_fsm_GatheringHostCandidatesDone_2_GatheringReflexiveCandidates_X_GatherReflexiveCandidates, "ICE_GatheringHostCandidatesDone_2_GatheringReflexiveCandidates_X_GatherReflexiveCandidates"),
+ // (GatheringReflexiveCandidates) -> (Success) -> GatheringReflexiveCandidatesDone
+ TSK_FSM_ADD_ALWAYS(_fsm_state_GatheringReflexiveCandidates, _fsm_action_Success, _fsm_state_GatheringReflexiveCandidatesDone, _tnet_ice_ctx_fsm_GatheringReflexiveCandidates_2_GatheringReflexiveCandidatesDone_X_Success, "ICE_fsm_GatheringReflexiveCandidates_2_GatheringReflexiveCandidatesDone_X_Success"),
+ // (GatheringReflexiveCandidates) -> (Failure) -> Terminated
+ TSK_FSM_ADD_ALWAYS(_fsm_state_GatheringReflexiveCandidates, _fsm_action_Failure, _fsm_state_Terminated, _tnet_ice_ctx_fsm_GatheringReflexiveCandidates_2_Terminated_X_Failure, "ICE_GatheringReflexiveCandidates_2_Terminated_X_Failure"),
+
+ // (GatheringReflexiveCandidatesDone) -> (GatherRelayCandidates) -> (GatheringRelayCandidates)
+ TSK_FSM_ADD_ALWAYS(_fsm_state_GatheringReflexiveCandidatesDone, _fsm_action_GatherRelayCandidates, _fsm_state_GatheringRelayCandidates, _tnet_ice_ctx_fsm_GatheringReflexiveCandidatesDone_2_GatheringRelayCandidates_X_GatherRelayCandidates, "ICE_GatheringReflexiveCandidatesDone_2_GatheringRelayCandidates_X_GatherRelayCandidates"),
+ // (GatheringHostCandidatesDone) -> (GatherRelayCandidates) -> (GatheringRelayCandidates)
+ TSK_FSM_ADD_ALWAYS(_fsm_state_GatheringHostCandidatesDone, _fsm_action_GatherRelayCandidates, _fsm_state_GatheringRelayCandidates, _tnet_ice_ctx_fsm_GatheringReflexiveCandidatesDone_2_GatheringRelayCandidates_X_GatherRelayCandidates, "ICE_GatheringHostCandidatesDone_2_GatheringRelayCandidates_X_GatherRelayCandidates"),
+ // (GatheringRelayCandidates) -> (Success) -> GatheringRelayCandidatesDone
+ TSK_FSM_ADD_ALWAYS(_fsm_state_GatheringRelayCandidates, _fsm_action_Success, _fsm_state_GatheringRelayCandidatesDone, _tnet_ice_ctx_fsm_GatheringRelayCandidates_2_GatheringRelayCandidatesDone_X_Success, "ICE_fsm_GatheringRelayCandidates_2_GatheringRelayCandidatesDone_X_Success"),
+ // (GatheringRelayCandidates) -> (Failure) -> Terminated
+ TSK_FSM_ADD_ALWAYS(_fsm_state_GatheringRelayCandidates, _fsm_action_Failure, _fsm_state_Terminated, _tnet_ice_ctx_fsm_GatheringRelayCandidates_2_Terminated_X_Failure, "ICE_GatheringRelayCandidates_2_Terminated_X_Failure"),
+
+ // (GatheringComplet) -> (ConnCheck) -> ConnChecking
+ TSK_FSM_ADD_ALWAYS(_fsm_state_GatheringCompleted, _fsm_action_ConnCheck, _fsm_state_ConnChecking, _tnet_ice_ctx_fsm_GatheringCompleted_2_ConnChecking_X_ConnCheck, "ICE_GatheringCompleted_2_ConnChecking_X_ConnCheck"),
+ // (ConnChecking) -> (Success) -> ConnCheckingCompleted
+ TSK_FSM_ADD_ALWAYS(_fsm_state_ConnChecking, _fsm_action_Success, _fsm_state_ConnCheckingCompleted, _tnet_ice_ctx_fsm_ConnChecking_2_ConnCheckingCompleted_X_Success, "ICE_ConnChecking_2_ConnCheckingCompleted_X_Success"),
+ // (ConnChecking) -> (Failure) -> Terminated
+ TSK_FSM_ADD_ALWAYS(_fsm_state_ConnChecking, _fsm_action_Failure, _fsm_state_Terminated, _tnet_ice_ctx_fsm_ConnChecking_2_Terminated_X_Failure, "ICE_ConnChecking_2_Terminated_X_Failure"),
+
+ // (Any) -> (GatheringComplet) -> GatheringCompleted
+ TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_GatheringComplet, _fsm_state_GatheringCompleted, _tnet_ice_ctx_fsm_Any_2_GatheringCompleted_X_GatheringComplet, "ICE_Any_2_GatheringCompleted_X_GatheringComplet"),
+ // (Any) -> (Cancel) -> Started
+ TSK_FSM_ADD_ALWAYS(tsk_fsm_state_any, _fsm_action_Cancel, _fsm_state_Started, _tnet_ice_ctx_fsm_Any_2_Started_X_Cancel, "ICE_Any_2_Started_X_Cancel"),
+ // (Any) -> (AnyNotStarted) -> Terminated
+ TSK_FSM_ADD(tsk_fsm_state_any, tsk_fsm_action_any, _tnet_ice_ctx_fsm_cond_NotStarted, _fsm_state_Terminated, _tnet_ice_ctx_fsm_Any_2_Terminated_X_AnyNotStarted, "ICE_fsm_Any_2_Terminated_X_AnyNotStarted")
+ );
+
+ return ctx;
+}
+
+int tnet_ice_ctx_set_userdata(tnet_ice_ctx_t* self, const void* userdata)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->userdata = userdata;
+ return 0;
+}
+
+// @deprecated: use "tnet_ice_ctx_add_server()"
+int tnet_ice_ctx_set_stun(
+ tnet_ice_ctx_t* self,
+ const char* server_addr,
+ uint16_t server_port,
+ const char* software,
+ const char* username,
+ const char* password)
+{
+ _tnet_ice_ctx_servers_clear(self);
+ return tnet_ice_ctx_add_server(
+ self,
+ "udp",
+ server_addr,
+ server_port,
+ (!tsk_strnullORempty(username) && !tsk_strnullORempty(password)), /* use_turn*/
+ tsk_true, /* use_stun*/
+ username,
+ password);
+}
+
+int tnet_ice_ctx_add_server(
+ struct tnet_ice_ctx_s* self,
+ const char* transport_proto, // "udp", "tcp", "tls", "ws", "wss"
+ const char* server_addr,
+ uint16_t server_port,
+ tsk_bool_t use_turn,
+ tsk_bool_t use_stun,
+ const char* username,
+ const char* password)
+{
+ tnet_socket_type_t socket_type;
+ tnet_ice_server_proto_t e_proto = tnet_ice_server_proto_none;
+ if (!self || tsk_strnullORempty(server_addr) || !server_port) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!use_turn && !use_stun) {
+ TSK_DEBUG_ERROR("'use_stun' or 'use_turn' must be true");
+ return -1;
+ }
+ if (use_stun) {
+ e_proto |= tnet_ice_server_proto_stun;
+ }
+ if (use_turn) {
+ e_proto |= tnet_ice_server_proto_turn;
+ }
+
+ if (tsk_striequals(transport_proto, "udp")) {
+ socket_type = self->use_ipv6 ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4;
+ }
+ else if (tsk_striequals(transport_proto, "tcp")) {
+ socket_type = self->use_ipv6 ? tnet_socket_type_tcp_ipv6 : tnet_socket_type_tcp_ipv4;
+ }
+ else if (tsk_striequals(transport_proto, "tls")) {
+ socket_type = self->use_ipv6 ? tnet_socket_type_tls_ipv6 : tnet_socket_type_tls_ipv4;
+ }
+ else if (tsk_striequals(transport_proto, "ws")) {
+ socket_type = self->use_ipv6 ? tnet_socket_type_ws_ipv6 : tnet_socket_type_ws_ipv4;
+ }
+ else if (tsk_striequals(transport_proto, "wss")) {
+ socket_type = self->use_ipv6 ? tnet_socket_type_wss_ipv6 : tnet_socket_type_wss_ipv4;
+ }
+ else {
+ TSK_DEBUG_ERROR("'%s' not a valid transport proto", transport_proto);
+ return -1;
+ }
+ return _tnet_ice_ctx_server_add(self, e_proto,
+ socket_type, server_addr, server_port,
+ kStunSoftware,
+ username, password);
+}
+
+int tnet_ice_ctx_set_sync_mode(tnet_ice_ctx_t* self, tsk_bool_t sync_mode)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->is_sync_mode = sync_mode;
+ return 0;
+}
+
+int tnet_ice_ctx_set_silent_mode(struct tnet_ice_ctx_s* self, tsk_bool_t silent_mode)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->is_silent_mode = silent_mode;
+ return 0;
+}
+
+// Whether to gather reflexive candidates
+int tnet_ice_ctx_set_stun_enabled(struct tnet_ice_ctx_s* self, tsk_bool_t stun_enabled)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->is_stun_enabled = stun_enabled;
+ return 0;
+}
+
+// Whether to gather relay candidates
+int tnet_ice_ctx_set_turn_enabled(struct tnet_ice_ctx_s* self, tsk_bool_t turn_enabled)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->is_turn_enabled = turn_enabled;
+ return 0;
+}
+
+int tnet_ice_ctx_start(tnet_ice_ctx_t* self)
+{
+ int ret;
+ tsk_bool_t timer_mgr_started = tsk_false;
+ tsk_bool_t runnable_started = tsk_false;
+ const char* err = tsk_null;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(self);
+
+ TSK_DEBUG_INFO("tnet_ice_ctx_start");
+
+ if (self->is_started){
+ ret = 0;
+ if (!self->is_active){
+ TSK_DEBUG_INFO("ICE restart");
+ ret = _tnet_ice_ctx_restart(self);
+ }
+ TSK_DEBUG_INFO("ICE already started");
+ tsk_safeobj_unlock(self);
+ return ret;
+ }
+
+ /* === Timer manager === */
+ if ((ret = tsk_timer_manager_start(self->h_timer_mgr))){
+ err = "Failed to start timer manager";
+ TSK_DEBUG_ERROR("%s", err);
+ goto bail;
+ }
+ timer_mgr_started = tsk_true;
+
+ /* === Runnable === */
+ TSK_RUNNABLE(self)->run = _tnet_ice_ctx_run;
+ if ((ret = tsk_runnable_start(TSK_RUNNABLE(self), tnet_ice_event_def_t))){
+ err = "Failed to start runnable";
+ TSK_DEBUG_ERROR("%s", err);
+ goto bail;
+ }
+ runnable_started = tsk_true;
+
+ self->is_started = tsk_true; // needed by FSM -> "Must" be before fsm_ast()
+ self->is_active = tsk_true;
+
+ if ((ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_GatherHostCandidates))){
+ err = "FSM execution failed";
+ TSK_DEBUG_ERROR("%s", err);
+ goto bail;
+ }
+
+bail:
+ tsk_safeobj_unlock(self);
+
+ if (ret){
+ _tnet_ice_ctx_signal_async(self, tnet_ice_event_type_start_failed, err);
+ if (timer_mgr_started){
+ tsk_timer_manager_stop(self->h_timer_mgr);
+ }
+ if (runnable_started){
+ tsk_runnable_stop(TSK_RUNNABLE(self));
+ }
+ self->is_started = tsk_false;
+ self->is_active = tsk_false;
+ }
+ return ret;
+}
+
+// register callback to call when we receive early RTP packets while negotaiating ICE pairs
+int tnet_ice_ctx_rtp_callback(tnet_ice_ctx_t* self, tnet_ice_rtp_callback_f rtp_callback, const void* rtp_callback_data)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ self->rtp_callback_data = rtp_callback_data;
+ self->rtp_callback = rtp_callback;
+ return 0;
+}
+
+// timeout (millis): <=0 to disable
+int tnet_ice_ctx_set_concheck_timeout(tnet_ice_ctx_t* self, int64_t timeout)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ self->concheck_timeout = (timeout <= 0 ? LONG_MAX : timeout);
+
+ return 0;
+}
+
+// @param candidates (candidate \r\n)+
+int tnet_ice_ctx_set_remote_candidates_2(struct tnet_ice_ctx_s* self, const char* candidates, const char* ufrag, const char* pwd, tsk_bool_t is_controlling, tsk_bool_t is_ice_jingle, tsk_bool_t use_rtcpmux)
+{
+ int ret = 0;
+ char *v, *copy, *saveptr;
+ tsk_size_t size, idx = 0;
+ tsk_bool_t exists;
+ tnet_ice_candidate_t* candidate;
+ tsk_strings_L_t *added_candidates = tsk_null;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ self->is_controlling = is_controlling;
+ self->is_ice_jingle = is_ice_jingle;
+ tnet_ice_ctx_set_rtcpmux(self, use_rtcpmux);
+
+ if (tsk_strnullORempty(candidates)) {
+ // remote party is ICE-lite or doesn't support ICE
+ return tnet_ice_ctx_cancel(self);
+ }
+
+ TSK_DEBUG_INFO("tnet_ice_ctx_set_remote_candidates(ufrag=%s, pwd=%s, is_controlling=%d, is_ice_jingle=%d, use_rtcpmux=%d)",
+ ufrag, pwd, is_controlling, is_ice_jingle, use_rtcpmux);
+
+ tsk_list_lock(self->candidates_pairs);
+ if (!TSK_LIST_IS_EMPTY(self->candidates_pairs)) {
+ TSK_DEBUG_WARN("Adding Remote ICE candidates after pairs building");
+ }
+ tsk_list_unlock(self->candidates_pairs);
+
+ // active if remote is full-ICE
+ // in all case we are always full-ICE
+ // self->is_active = tsk_true;
+
+ tsk_list_lock(self->candidates_remote);
+
+ // clear old candidates
+ tsk_list_clear_items(self->candidates_remote);
+
+ copy = tsk_strdup(candidates);
+ size = (tsk_size_t)tsk_strlen(copy);
+ do {
+ v = tsk_strtok_r(&copy[idx], "\r\n", &saveptr);
+ idx += tsk_strlen(v) + 2;
+ if (v && (candidate = tnet_ice_candidate_parse(v))) {
+ exists = tsk_false;
+ if (!added_candidates) {
+ added_candidates = tsk_list_create();
+ }
+ if (ufrag && pwd) {
+ tnet_ice_candidate_set_credential(candidate, ufrag, pwd);
+ }
+ if (added_candidates) {
+ tsk_string_t* str_cand = tsk_string_create(tnet_ice_candidate_tostring(candidate));
+ if (str_cand) {
+ if ((exists = !!tsk_list_find_object_by_data(added_candidates, str_cand))) {
+ TSK_DEBUG_INFO("Remote candidate [[%s]] is duplicated ...skipping", str_cand->value);
+ }
+ else {
+ tsk_list_push_back_data(added_candidates, (void**)&str_cand);
+ }
+ TSK_OBJECT_SAFE_FREE(str_cand);
+ }
+ }
+ if (!exists) {
+ tsk_list_push_descending_data(self->candidates_remote, (void**)&candidate);
+ }
+ TSK_OBJECT_SAFE_FREE(candidate);
+ }
+ } while (v && (idx < size));
+
+ tsk_list_unlock(self->candidates_remote);
+
+ TSK_FREE(copy);
+ TSK_OBJECT_SAFE_FREE(added_candidates);
+
+ if (!tnet_ice_ctx_is_connected(self) && tnet_ice_ctx_got_local_candidates(self) && !TSK_LIST_IS_EMPTY(self->candidates_remote)) {
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_ConnCheck);
+ }
+ return ret;
+}
+
+// @param candidates (candidate \r\n)+
+int tnet_ice_ctx_set_remote_candidates(tnet_ice_ctx_t* self, const char* candidates, const char* ufrag, const char* pwd, tsk_bool_t is_controlling, tsk_bool_t is_ice_jingle)
+{
+ return tnet_ice_ctx_set_remote_candidates_2(self, candidates, ufrag, pwd, is_controlling, is_ice_jingle, self->use_rtcpmux);
+}
+
+int tnet_ice_ctx_set_rtcpmux(tnet_ice_ctx_t* self, tsk_bool_t use_rtcpmux)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (self->is_connchecking && self->use_rtcpmux != use_rtcpmux) {
+ TSK_DEBUG_WARN("use_rtcpmux changed(%d->%d) while connchecking", self->use_rtcpmux, use_rtcpmux);
+ }
+ self->use_rtcpmux = use_rtcpmux;
+ return 0;
+}
+
+int tnet_ice_ctx_set_ssl_certs(struct tnet_ice_ctx_s* self, const char* path_priv, const char* path_pub, const char* path_ca, tsk_bool_t verify)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_strupdate(&self->ssl.path_priv, path_priv);
+ tsk_strupdate(&self->ssl.path_pub, path_pub);
+ tsk_strupdate(&self->ssl.path_ca, path_ca);
+ self->ssl.verify = verify;
+ return 0;
+}
+
+tsk_size_t tnet_ice_ctx_count_local_candidates(const tnet_ice_ctx_t* self)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
+ return tsk_list_count(self->candidates_local, tsk_null, tsk_null);
+}
+
+tsk_bool_t tnet_ice_ctx_got_local_candidates(const tnet_ice_ctx_t* self)
+{
+ tsk_fsm_state_id curr_state;
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_false;
+ }
+ if (!self->is_started){
+ return tsk_false;
+ }
+
+ curr_state = tsk_fsm_get_current_state(self->fsm);
+
+ return (curr_state >= _fsm_state_GatheringCompleted && curr_state < _fsm_state_Terminated);
+}
+
+const tnet_ice_candidate_t* tnet_ice_ctx_get_local_candidate_at(const tnet_ice_ctx_t* self, tsk_size_t index)
+{
+ const tsk_list_item_t *item;
+ tsk_size_t pos = 0;
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ tsk_list_foreach(item, self->candidates_local){
+ if (pos++ == index){
+ return (const tnet_ice_candidate_t*)item->data;
+ }
+ }
+ return tsk_null;
+}
+
+tsk_bool_t tnet_ice_ctx_is_started(const tnet_ice_ctx_t* self)
+{
+ return (self && self->is_started);
+}
+
+// says if ICE is enabled
+// doesn't say if the connection has been negotiated (see is_connecte())
+tsk_bool_t tnet_ice_ctx_is_active(const tnet_ice_ctx_t* self)
+{
+ return (self && self->is_started && self->is_active);
+}
+
+tsk_bool_t tnet_ice_ctx_is_turn_rtp_active(const struct tnet_ice_ctx_s* self)
+{
+ tsk_bool_t b_active;
+ return tnet_ice_ctx_is_active(self)
+ && self->turn.ss_nominated_rtp
+ && tnet_turn_session_is_active(self->turn.ss_nominated_rtp, self->turn.peer_id_rtp, &b_active) == 0
+ && b_active;
+}
+
+tsk_bool_t tnet_ice_ctx_is_turn_rtcp_active(const struct tnet_ice_ctx_s* self)
+{
+ if (self->use_rtcpmux) {
+ return tnet_ice_ctx_is_turn_rtp_active(self);
+ }
+ else {
+ tsk_bool_t b_active;
+ return tnet_ice_ctx_is_active(self)
+ && self->turn.ss_nominated_rtcp
+ && tnet_turn_session_is_active(self->turn.ss_nominated_rtcp, self->turn.peer_id_rtcp, &b_active) == 0
+ && b_active;
+ }
+}
+
+// says if media can start in both direction
+tsk_bool_t tnet_ice_ctx_is_connected(const tnet_ice_ctx_t* self)
+{
+ return (self && self->have_nominated_symetric);
+}
+
+tsk_bool_t tnet_ice_ctx_is_can_send(const tnet_ice_ctx_t* self)
+{
+ return (self && self->have_nominated_offer);
+}
+
+tsk_bool_t tnet_ice_ctx_is_can_recv(const tnet_ice_ctx_t* self)
+{
+ return (self && self->have_nominated_answer);
+}
+
+tsk_bool_t tnet_ice_ctx_use_ipv6(const tnet_ice_ctx_t* self)
+{
+ return (self && self->use_ipv6);
+}
+
+tsk_bool_t tnet_ice_ctx_use_rtcp(const tnet_ice_ctx_t* self)
+{
+ return (self && self->use_rtcp);
+}
+
+int tnet_ice_ctx_get_nominated_symetric_candidates(const tnet_ice_ctx_t* self, uint32_t comp_id,
+ const tnet_ice_candidate_t** candidate_offer,
+ const tnet_ice_candidate_t** candidate_answer_src,
+ const tnet_ice_candidate_t** candidate_answer_dest)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return tnet_ice_pairs_get_nominated_symetric_candidates(self->candidates_pairs, comp_id, candidate_offer, candidate_answer_src, candidate_answer_dest);
+}
+
+int tnet_ice_ctx_recv_stun_message(tnet_ice_ctx_t* self, const void* data, tsk_size_t size, tnet_fd_t local_fd, const struct sockaddr_storage* remote_addr, tsk_bool_t *role_conflict)
+{
+ static const tnet_ice_pair_t* kNullPair = tsk_null; // means seach for the pair using local_fd and remote_addr
+ return _tnet_ice_ctx_recv_stun_message_for_pair(self, kNullPair, data, size, local_fd, remote_addr, role_conflict);
+}
+
+int tnet_ice_ctx_send_turn_rtp(struct tnet_ice_ctx_s* self, const void* data, tsk_size_t size)
+{
+ return _tnet_ice_ctx_send_turn_raw(self, self->turn.ss_nominated_rtp, self->turn.peer_id_rtp, data, size);
+}
+
+int tnet_ice_ctx_send_turn_rtcp(struct tnet_ice_ctx_s* self, const void* data, tsk_size_t size)
+{
+ return self->use_rtcpmux
+ ? tnet_ice_ctx_send_turn_rtp(self, data, size)
+ : _tnet_ice_ctx_send_turn_raw(self, self->turn.ss_nominated_rtcp, self->turn.peer_id_rtcp, data, size);
+}
+
+int tnet_ice_ctx_turn_get_bytes_count(const struct tnet_ice_ctx_s* self, uint64_t* bytes_in, uint64_t* bytes_out)
+{
+ int ret;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ ret = tnet_turn_session_get_bytes_count(self->turn.ss_nominated_rtp, bytes_in, bytes_out);
+ if (ret == 0 && !self->use_rtcpmux) {
+ uint64_t _bytes_in, _bytes_out;
+ ret = tnet_turn_session_get_bytes_count(self->turn.ss_nominated_rtcp, &_bytes_in, &_bytes_out);
+ if (ret == 0) {
+ if (bytes_in) *bytes_in += _bytes_in;
+ if (bytes_out) *bytes_out += _bytes_out;
+ }
+ }
+ return ret;
+}
+
+const char* tnet_ice_ctx_get_ufrag(const struct tnet_ice_ctx_s* self)
+{
+ return (self && self->ufrag) ? self->ufrag : tsk_null;
+}
+
+const char* tnet_ice_ctx_get_pwd(const struct tnet_ice_ctx_s* self)
+{
+ return (self && self->pwd) ? self->pwd : tsk_null;
+}
+
+int tnet_ice_ctx_set_proxy_auto_detect(struct tnet_ice_ctx_s* self, tsk_bool_t auto_detect)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->proxy.auto_detect = auto_detect;
+ return 0;
+}
+
+int tnet_ice_ctx_set_proxy_info(struct tnet_ice_ctx_s* self, enum tnet_proxy_type_e type, const char* host, tnet_port_t port, const char* login, const char* password)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!self->proxy.info && !(self->proxy.info = tnet_proxyinfo_create())) {
+ return -2;
+ }
+ self->proxy.info->type = type;
+ self->proxy.info->port = port;
+ tsk_strupdate(&self->proxy.info->hostname, host);
+ tsk_strupdate(&self->proxy.info->username, login);
+ tsk_strupdate(&self->proxy.info->password, password);
+ return 0;
+}
+
+// cancels the ICE processing without stopping the process
+int tnet_ice_ctx_cancel(tnet_ice_ctx_t* self)
+{
+ int ret;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(self);
+ if (tsk_fsm_get_current_state(self->fsm) == _fsm_state_Started) {
+ // Do nothing if already in the "started" state
+ ret = 0;
+ goto bail;
+ }
+
+ self->is_active = tsk_false;
+ self->have_nominated_symetric = tsk_false;
+ self->have_nominated_answer = tsk_false;
+ self->have_nominated_offer = tsk_false;
+ tsk_condwait_broadcast(self->condwait_pairs);
+ if (self->turn.condwait) {
+ ret = tsk_condwait_broadcast(self->turn.condwait);
+ }
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_Cancel);
+
+bail:
+ tsk_safeobj_unlock(self);
+ return ret;
+}
+
+int tnet_ice_ctx_stop(tnet_ice_ctx_t* self)
+{
+ int ret;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(self);
+ if (!self->is_started) {
+ ret = 0;
+ goto bail;
+ }
+
+ self->is_started = tsk_false;
+ tsk_condwait_broadcast(self->condwait_pairs);
+ if (self->turn.condwait) {
+ ret = tsk_condwait_broadcast(self->turn.condwait);
+ }
+ ret = tsk_timer_manager_stop(self->h_timer_mgr);
+ ret = tsk_runnable_stop(TSK_RUNNABLE(self));
+
+bail:
+ tsk_safeobj_unlock(self);
+ return ret;
+}
+
+//--------------------------------------------------------
+// == STATE MACHINE BEGIN ==
+//--------------------------------------------------------
+
+// Started -> (GatherHostCandidates) -> (GatheringHostCandidates)
+static int _tnet_ice_ctx_fsm_Started_2_GatheringHostCandidates_X_GatherHostCandidates(va_list *app)
+{
+ int ret = 0;
+ tnet_ice_ctx_t* self;
+ tnet_addresses_L_t* addresses;
+ const tsk_list_item_t *item;
+ const tnet_address_t* address;
+ tnet_ice_candidate_t* candidate;
+ tnet_socket_t* socket_rtp = tsk_null;
+ tnet_socket_t* socket_rtcp = tsk_null;
+ tnet_socket_type_t socket_type;
+ uint16_t local_pref, curr_local_pref;
+ tnet_ip_t best_local_ip;
+ tsk_bool_t check_best_local_ip;
+ static const tsk_bool_t dnsserver = tsk_false;
+ static const long if_index_any = -1; // any interface
+ static const char* destination = "doubango.org";
+
+ self = va_arg(*app, tnet_ice_ctx_t *);
+ socket_type = self->use_ipv6 ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4;
+
+ addresses = tnet_get_addresses((self->use_ipv6 ? AF_INET6 : AF_INET), self->unicast, self->anycast, self->multicast, dnsserver, if_index_any);
+ if (!addresses || TSK_LIST_IS_EMPTY(addresses)){
+ TSK_DEBUG_ERROR("Failed to get addresses");
+ ret = -1;
+ goto bail;
+ }
+
+
+ check_best_local_ip = (tnet_getbestsource(destination, 5060, socket_type, &best_local_ip) == 0);
+ curr_local_pref = local_pref = check_best_local_ip ? 0xFFFE : 0xFFFF;
+
+ // lock-list
+ tsk_list_lock(self->candidates_local);
+ // clear-list
+ tsk_list_clear_items(self->candidates_local);
+
+ tsk_list_foreach(item, addresses){
+ if (!(address = item->data)){
+ continue;
+ }
+
+ // Skip loopback address to avoid problems :)
+ if ((address->family == AF_INET && tsk_striequals(address->ip, "127.0.0.1")) || (address->family == AF_INET6 && tsk_striequals(address->ip, "::1"))){
+ continue;
+ }
+
+ // host candidates
+ ret = tnet_ice_utils_create_sockets(socket_type,
+ address->ip, &socket_rtp,
+ self->use_rtcp ? &socket_rtcp : tsk_null);
+ if (ret == 0){
+ const char* foundation_rtp = foundation_default;
+ tsk_list_lock(self->candidates_local);
+ if (socket_rtp){
+ if ((candidate = tnet_ice_candidate_create(tnet_ice_cand_type_host, socket_rtp, self->is_ice_jingle, tsk_true, self->is_video, self->ufrag, self->pwd, foundation_default))){
+ foundation_rtp = (const char*)candidate->foundation;
+ if (check_best_local_ip && (candidate->socket && (tsk_striequals(candidate->socket->ip, best_local_ip)))){
+ curr_local_pref = 0xFFFF;
+ check_best_local_ip = tsk_false;
+ tnet_ice_candidate_set_local_pref(candidate, curr_local_pref);
+ tsk_list_push_front_data(self->candidates_local, (void**)&candidate);
+ }
+ else{
+ curr_local_pref = local_pref--;
+ tnet_ice_candidate_set_local_pref(candidate, curr_local_pref);
+ tsk_list_push_back_data(self->candidates_local, (void**)&candidate);
+ }
+ }
+ }
+ if (socket_rtcp){
+ if ((candidate = tnet_ice_candidate_create(tnet_ice_cand_type_host, socket_rtcp, self->is_ice_jingle, tsk_false, self->is_video, self->ufrag, self->pwd, foundation_rtp))){
+ tnet_ice_candidate_set_local_pref(candidate, curr_local_pref);
+ tsk_list_push_back_data(self->candidates_local, (void**)&candidate);
+ }
+ }
+ tsk_list_unlock(self->candidates_local);
+ }
+
+ TSK_OBJECT_SAFE_FREE(socket_rtp);
+ TSK_OBJECT_SAFE_FREE(socket_rtcp);
+
+ // break if no longer running
+ if (!self->is_started){
+ break;
+ }
+
+ TSK_DEBUG_INFO("local ip address = %s", address->ip);
+ }
+
+ // unlock-list
+ tsk_list_unlock(self->candidates_local);
+
+bail:
+ if (self->is_started){
+ if (ret == 0 && !TSK_LIST_IS_EMPTY(self->candidates_local)){
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_Success);
+ }
+ else{
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_Failure);
+ }
+ }
+
+ TSK_OBJECT_SAFE_FREE(addresses);
+ return ret;
+}
+
+// GatheringHostCandidates -> (Success) -> (GatheringHostCandidatesDone)
+static int _tnet_ice_ctx_fsm_GatheringHostCandidates_2_GatheringHostCandidatesDone_X_Success(va_list *app)
+{
+ int ret;
+ tnet_ice_ctx_t* self;
+
+ self = va_arg(*app, tnet_ice_ctx_t *);
+
+ ret = _tnet_ice_ctx_signal_async(self, tnet_ice_event_type_gathering_host_candidates_succeed, "Gathering host candidates succeed");
+ if (ret == 0) {
+ if (self->is_stun_enabled && _tnet_ice_ctx_servers_count_by_proto(self, tnet_ice_server_proto_stun) > 0) {
+ TSK_DEBUG_INFO("ICE-STUN enabled and we have STUN servers");
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_GatherReflexiveCandidates);
+ }
+ else {
+ if (self->is_turn_enabled && _tnet_ice_ctx_servers_count_by_proto(self, tnet_ice_server_proto_turn) > 0) {
+ TSK_DEBUG_INFO("ICE-TURN enabled and we have STUN servers");
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_GatherRelayCandidates);
+ }
+ else {
+ TSK_DEBUG_INFO("Do not gather reflexive/relayed candidates because ICE-STUN/TURN is disabled or no server defined");
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_GatheringComplet);
+ }
+ }
+ }
+
+ return ret;
+}
+
+// GatheringHostCandidates -> (Failure) -> (Terminated)
+static int _tnet_ice_ctx_fsm_GatheringHostCandidates_2_Terminated_X_Failure(va_list *app)
+{
+ tnet_ice_ctx_t* self;
+
+ self = va_arg(*app, tnet_ice_ctx_t *);
+ return _tnet_ice_ctx_signal_async(self, tnet_ice_event_type_gathering_host_candidates_failed, "Gathering host candidates failed");
+}
+
+// GatheringHostCandidatesDone -> (GatherReflexiveCandidate) -> GatheringReflexiveCandidates
+static int _tnet_ice_ctx_fsm_GatheringHostCandidatesDone_2_GatheringReflexiveCandidates_X_GatherReflexiveCandidates(va_list *app)
+{
+ /* RFC 5389 - 7.2.1. Sending over UDP
+ STUN indications are not retransmitted; thus, indication transactions over UDP
+ are not reliable.
+ */
+ int ret = 0;
+ tnet_ice_servers_L_t* ice_servers = tsk_null;
+ tnet_ice_server_t* ice_server;
+ tnet_ice_ctx_t* self;
+ uint16_t i, k, rc;
+ struct timeval tv;
+ tnet_stun_pkt_resp_t *response = tsk_null;
+ const tsk_list_item_t *item, *item_server;
+ tnet_ice_candidate_t* candidate;
+ tnet_fd_t fds[kIceCandidatesCountMax] = { TNET_INVALID_FD }; // -1, then zeros
+ tnet_fd_t fds_skipped[kIceCandidatesCountMax] = { TNET_INVALID_FD }; // -1, then zeros
+ uint16_t fds_count = 0;
+ tnet_fd_t fd_max = -1;
+ fd_set set;
+ tsk_size_t srflx_addr_count_added = 0, srflx_addr_count_skipped = 0, host_addr_count = 0;
+ long tv_sec, tv_usec; //very important to save these values as timeval could be modified by select() - happens on iOS -
+
+ self = va_arg(*app, tnet_ice_ctx_t *);
+
+ // Get ICE servers to use to gather reflexive candidates
+ ice_servers = _tnet_ice_ctx_servers_copy(self, tnet_ice_server_proto_stun);
+ if (!ice_servers || TSK_LIST_IS_EMPTY(ice_servers)) { // not expected to be null or empty because we checked the number of such servers before calling this transition
+ TSK_DEBUG_WARN("No valid STUN server could be used to gather reflexive candidates");
+ goto bail;
+ }
+
+ // set all default values to -1
+ // = {{ -1 }} will only set the first element
+ for (i = 0; i < sizeof(fds) / sizeof(fds[0]); ++i) {
+ fds[i] = TNET_INVALID_FD;
+ }
+ for (i = 0; i < sizeof(fds_skipped) / sizeof(fds_skipped[0]); ++i) {
+ fds_skipped[i] = TNET_INVALID_FD;
+ }
+
+ rc = self->Rc;
+ tv.tv_sec = tv_sec = 0;
+ tv.tv_usec = tv_usec = 0;
+
+ // load fds for both rtp and rtcp sockets
+ tsk_list_foreach(item, self->candidates_local) {
+ if (!(candidate = item->data)) {
+ continue;
+ }
+
+ ++host_addr_count;
+ if ((fds_count < sizeof(fds) / sizeof(fds[0])) && candidate->socket) {
+ fds[fds_count++] = candidate->socket->fd;
+ if (candidate->socket->fd > fd_max) {
+ fd_max = candidate->socket->fd;
+ }
+ }
+ }
+
+
+ /* RFC 5389 - 7.2.1. Sending over UDP
+ A client SHOULD retransmit a STUN request message starting with an
+ interval of RTO ("Retransmission TimeOut"), doubling after each
+ retransmission.
+
+ e.g. 0 ms, 500 ms, 1500 ms, 3500 ms, 7500ms, 15500 ms, and 31500 ms
+ */
+ for (i = 0; (i < rc && self->is_started && ((srflx_addr_count_added + srflx_addr_count_skipped) < host_addr_count)); ++i) {
+ // Try gathering the reflexive candidate for each server
+ tsk_list_foreach(item_server, ice_servers) {
+ if (!self->is_started) {
+ break;
+ }
+ if (!(ice_server = item_server->data)) {
+ continue; // must never happen
+ }
+ if (i == 0) {
+ ice_server->rto = 0;
+ }
+ else if (i == 1) {
+ ice_server->rto = self->RTO;
+ }
+ // else // ice_server->rto <<= 1;
+ tv_sec = ice_server->rto / 1000;
+ tv_usec = (ice_server->rto % 1000) * 1000;
+ if (tv_usec >= 1000000) { // > 1000000 is invalid and produce EINVAL when passed to select(iOS)
+ tv_usec -= 1000000;
+ tv_sec++;
+ }
+ // restore values for new select
+ tv.tv_sec = tv_sec;
+#if TNET_UNDER_APPLE
+ tv.tv_usec = (__darwin_suseconds_t)tv_usec;
+#else
+ tv.tv_usec = tv_usec;
+#endif
+
+ TSK_DEBUG_INFO("ICE reflexive candidates gathering ...srv_addr=%s,srv_port=%u,tv_sec=%lu,tv_usec=%lu,rto=%d", ice_server->str_server_addr, ice_server->u_server_port, tv_sec, tv_usec, ice_server->rto);
+
+ FD_ZERO(&set);
+ for (k = 0; k < fds_count; ++k) {
+ FD_SET(fds[k], &set);
+ }
+
+ // sends STUN binding requets
+ tsk_list_foreach(item, self->candidates_local){
+ if (!(candidate = (tnet_ice_candidate_t*)item->data)) {
+ continue;
+ }
+ if (candidate->socket && tsk_strnullORempty(candidate->stun.srflx_addr)) {
+ ret = tnet_ice_candidate_send_stun_bind_request(candidate, &ice_server->obj_server_addr, ice_server->str_username, ice_server->str_password);
+ }
+ }
+
+ if ((ret = select(fd_max + 1, &set, NULL, NULL, &tv)) < 0) {
+ TSK_DEBUG_ERROR("select() failed with error code = %d", tnet_geterrno());
+ goto bail;
+ }
+ else if (ret == 0) {
+ // timeout
+ TSK_DEBUG_INFO("STUN request timedout at %d, rc = %d, rto=%d", i, rc - 1, ice_server->rto);
+ ice_server->rto <<= 1;
+ continue;
+ }
+ else if (ret > 0) {
+ // there is data to read
+ for (k = 0; k < fds_count; ++k) {
+ tnet_fd_t fd = fds[k];
+ if (FD_ISSET(fd, &set)) {
+ unsigned int len = 0;
+ void* data = 0;
+ const tnet_ice_candidate_t* candidate_curr;
+
+ // Check how many bytes are pending
+ if ((ret = tnet_ioctlt(fd, FIONREAD, &len)) < 0) {
+ TSK_DEBUG_ERROR("tnet_ioctlt() failed");
+ continue;
+ }
+
+ if (len == 0) {
+ TSK_DEBUG_INFO("tnet_ioctlt() retured zero bytes");
+ continue;
+ }
+
+ // Receive pending data
+ data = tsk_calloc(len, sizeof(uint8_t));
+ if ((ret = tnet_sockfd_recv(fd, data, len, 0)) < 0) {
+ TSK_FREE(data);
+
+ TSK_DEBUG_ERROR("Recving STUN dgrams failed with error code:%d", tnet_geterrno());
+ continue;
+ }
+
+ // Parse the incoming response
+ if ((ret = tnet_stun_pkt_read(data, (tsk_size_t)ret, &response))) {
+ TSK_FREE(data);
+ continue;
+ }
+ TSK_FREE(data);
+ if (response) {
+ ret = 0;
+ if ((candidate_curr = tnet_ice_candidate_find_by_fd(self->candidates_local, fd))) {
+ if (tsk_strnullORempty(candidate_curr->stun.srflx_addr)) { // "srflx" candidate?
+ ret = tnet_ice_candidate_process_stun_response((tnet_ice_candidate_t*)candidate_curr, response, fd);
+ if (!tsk_strnullORempty(candidate_curr->stun.srflx_addr)) { // ...and now (after processing the response)...is it "srflx" candidate?
+ if (tsk_striequals(candidate_curr->connection_addr, candidate_curr->stun.srflx_addr) && candidate_curr->port == candidate_curr->stun.srflx_port) {
+ tsk_size_t j;
+ tsk_bool_t already_skipped = tsk_false;
+ /* refc 5245- 4.1.3. Eliminating Redundant Candidates
+
+ Next, the agent eliminates redundant candidates. A candidate is
+ redundant if its transport address equals another candidate, and its
+ base equals the base of that other candidate. Note that two
+ candidates can have the same transport address yet have different
+ bases, and these would not be considered redundant. Frequently, a
+ server reflexive candidate and a host candidate will be redundant
+ when the agent is not behind a NAT. The agent SHOULD eliminate the
+ redundant candidate with the lower priority. */
+ for (j = 0; (fds_skipped[j] != TNET_INVALID_FD && j < (sizeof(fds_skipped) / sizeof(fds_skipped[0]))); ++j) {
+ if (fds_skipped[j] == fd) {
+ already_skipped = tsk_true;
+ break;
+ }
+ }
+
+ if (!already_skipped) {
+ ++srflx_addr_count_skipped;
+ fds_skipped[j] = fd;
+ }
+ TSK_DEBUG_INFO("Skipping redundant candidate address=%s and port=%d, fd=%d, already_skipped(%u)=%s",
+ candidate_curr->stun.srflx_addr,
+ candidate_curr->stun.srflx_port,
+ fd,
+ (unsigned)j, already_skipped ? "yes" : "no");
+ }
+ else {
+ char* foundation = tsk_strdup(TNET_ICE_CANDIDATE_TYPE_SRFLX);
+ tnet_ice_candidate_t* new_cand;
+ tsk_strcat(&foundation, (const char*)candidate_curr->foundation);
+ new_cand = tnet_ice_candidate_create(tnet_ice_cand_type_srflx, candidate_curr->socket, candidate_curr->is_ice_jingle, candidate_curr->is_rtp, self->is_video, self->ufrag, self->pwd, foundation);
+ TSK_FREE(foundation);
+ if (new_cand) {
+ ++srflx_addr_count_added;
+ tsk_list_lock(self->candidates_local);
+ tnet_ice_candidate_set_rflx_addr(new_cand, candidate_curr->stun.srflx_addr, candidate_curr->stun.srflx_port);
+ tsk_list_push_descending_data(self->candidates_local, (void**)&new_cand);
+ tsk_list_unlock(self->candidates_local);
+ }
+ }
+ }
+ }
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(response);
+ }
+ }
+ }
+ else {
+ continue;
+ }
+ } // tsk_list_foreach (item, ice_servers)...
+ } // for (i = 0; (i < rc....
+
+bail:
+ TSK_DEBUG_INFO("srflx_addr_count_added=%u, srflx_addr_count_skipped=%u", (unsigned)srflx_addr_count_added, (unsigned)srflx_addr_count_skipped);
+ if ((srflx_addr_count_added + srflx_addr_count_skipped) > 0) ret = 0; // Hack the returned value if we have at least one success (happens when timeouts)
+ if (self->is_started) {
+ if (ret == 0) {
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_Success);
+ }
+ else{
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_Failure);
+ }
+ }
+
+ tsk_list_foreach(item, self->candidates_local) {
+ if (!(candidate = (tnet_ice_candidate_t*)item->data)) {
+ continue;
+ }
+ TSK_DEBUG_INFO("Candidate: %s", tnet_ice_candidate_tostring(candidate));
+ }
+ TSK_OBJECT_SAFE_FREE(ice_servers);
+ return ret;
+}
+
+// GatheringReflexiveCandidates -> (Success) -> GatheringReflexiveCandidatesDone
+static int _tnet_ice_ctx_fsm_GatheringReflexiveCandidates_2_GatheringReflexiveCandidatesDone_X_Success(va_list *app)
+{
+ tnet_ice_ctx_t* self;
+
+ self = va_arg(*app, tnet_ice_ctx_t *);
+
+ if (self->is_started) {
+ int ret = _tnet_ice_ctx_signal_async(self, tnet_ice_event_type_gathering_reflexive_candidates_succeed, "Gathering reflexive candidates succeed");
+ if (ret == 0) {
+ enum _fsm_action_e action_next = _fsm_action_GatheringComplet;
+ if (self->is_turn_enabled) {
+ if (_tnet_ice_ctx_servers_count_by_proto(self, tnet_ice_server_proto_turn) == 0) {
+ TSK_DEBUG_WARN("TURN is enabled but no TURN server could be found");
+ }
+ else {
+ action_next = _fsm_action_GatherRelayCandidates;
+ }
+ }
+ ret = _tnet_ice_ctx_fsm_act(self, action_next);
+ }
+ return ret;
+ }
+ else {
+ return -1;
+ }
+}
+
+// GatheringReflexiveCandidates -> (Failure) -> Terminated
+static int _tnet_ice_ctx_fsm_GatheringReflexiveCandidates_2_Terminated_X_Failure(va_list *app)
+{
+ tnet_ice_ctx_t* self = va_arg(*app, tnet_ice_ctx_t *);
+ return _tnet_ice_ctx_signal_async(self, tnet_ice_event_type_gathering_reflexive_candidates_failed, "Gathering reflexive candidates failed");
+}
+
+// GatheringReflexiveCandidatesDone -> (GatherRelayCandidates) -> GatheringRelayCandidates
+static int _tnet_ice_ctx_fsm_GatheringReflexiveCandidatesDone_2_GatheringRelayCandidates_X_GatherRelayCandidates(va_list *app)
+{
+ tnet_ice_ctx_t* self = va_arg(*app, tnet_ice_ctx_t *);
+ int ret = 0;
+ tsk_list_item_t *item, *item_server = tsk_null;
+ tnet_ice_candidate_t* candidate;
+ uint16_t i, rto, rc;
+ tsk_size_t relay_addr_count_ok = 0, relay_addr_count_nok = 0, relay_addr_count_added = 0, host_addr_count = 0;
+ uint64_t u_t0, u_t1;
+ enum tnet_stun_state_e e_tunrn_state;
+ tnet_ice_servers_L_t* ice_servers = tsk_null;
+ tnet_ice_server_t* ice_server;
+ tnet_ice_candidates_L_t* candidates_local_copy = tsk_null;;
+
+ // Create TURN condwait handle if not already done
+ if (!self->turn.condwait && !(self->turn.condwait = tsk_condwait_create())) {
+ TSK_DEBUG_ERROR("Failed to create TURN condwait handle");
+ ret = -2;
+ goto bail;
+ }
+
+ // Copy local ICE candidates
+ tsk_list_lock(self->candidates_local);
+ candidates_local_copy = tsk_list_clone(self->candidates_local);
+ tsk_list_unlock(self->candidates_local);
+
+ // Take reference to the TURN servers
+ ice_servers = _tnet_ice_ctx_servers_copy(self, tnet_ice_server_proto_turn);
+ if (!ice_servers || TSK_LIST_IS_EMPTY(ice_servers)) {
+ TSK_DEBUG_WARN("TURN enabled but no server could be found"); // should never happen...but who knows?
+ goto bail;
+ }
+next_server:
+ if (!self->is_started) {
+ goto bail;
+ }
+ relay_addr_count_ok = 0, relay_addr_count_nok = 0, relay_addr_count_added = 0, host_addr_count = 0;
+ if (!item_server) {
+ item_server = ice_servers->head;
+ }
+ else {
+ item_server = item_server->next;
+ }
+ if (!item_server) {
+ TSK_DEBUG_INFO("We have reached the end of TURN servers");
+ goto bail;
+ }
+ ice_server = (tnet_ice_server_t*)item_server->data;
+
+ // Create TURN sessions for each local host candidate
+ tsk_list_foreach(item, candidates_local_copy) {
+ if (!(candidate = item->data)) {
+ continue;
+ }
+ TSK_DEBUG_INFO("Gathering relay candidate: local addr=%s=%d, TURN server=%s:%d", candidate->connection_addr, candidate->port, ice_server->str_server_addr, ice_server->u_server_port);
+
+ // Destroy previvious TURN session (if exist)
+ TSK_OBJECT_SAFE_FREE(candidate->turn.ss);
+ if (candidate->type_e == tnet_ice_cand_type_host && candidate->socket) { // do not create TURN session for reflexive candidates
+ // create the TURN session
+ // FIXME: For now we support UDP relaying only (like Chrome): more info at https://groups.google.com/forum/#!topic/turn-server-project-rfc5766-turn-server/vR_2OAV9a_w
+ // This is not an issue even if both peers requires TCP/TLS connection to the TURN server. UDP relaying will be local to the servers.
+ //
+ static enum tnet_turn_transport_e __e_req_transport = tnet_turn_transport_udp; // We should create two TURN sessions: #1 UDP relay + #1 TCP relay
+ if ((ret = tnet_turn_session_create_4(candidate->socket, __e_req_transport, ice_server->str_server_addr, ice_server->u_server_port, ice_server->e_transport, &candidate->turn.ss))) {
+ continue;
+ }
+ // set TURN callback
+ if ((ret = tnet_turn_session_set_callback(candidate->turn.ss, _tnet_ice_ctx_turn_callback, self))) {
+ continue;
+ }
+ // set SSL certificates
+ if ((ret = tnet_turn_session_set_ssl_certs(candidate->turn.ss, self->ssl.path_priv, self->ssl.path_pub, self->ssl.path_ca, self->ssl.verify))) {
+ continue;
+ }
+ // WebProxy
+ if ((ret = tnet_turn_session_set_proxy_auto_detect(candidate->turn.ss, self->proxy.auto_detect))) {
+ continue;
+ }
+ if ((ret = tnet_turn_session_set_proxy_info(candidate->turn.ss, self->proxy.info))) {
+ continue;
+ }
+ // set TURN credentials
+ if ((ret = tnet_turn_session_set_cred(candidate->turn.ss, ice_server->str_username, ice_server->str_password))) {
+ continue;
+ }
+ // prepare()
+ if ((ret = tnet_turn_session_prepare(candidate->turn.ss))) {
+ continue;
+ }
+ // start()
+ if ((ret = tnet_turn_session_start(candidate->turn.ss))) {
+ continue;
+ }
+ // allocate()
+ if ((ret = tnet_turn_session_allocate(candidate->turn.ss))) {
+ continue;
+ }
+ ++host_addr_count;
+ }
+ } // tsk_list_foreach(item, self->candidates_local) {
+
+ rto = self->RTO;
+ rc = self->Rc;
+
+ for (i = 0; (i < rc && self->is_started && ((relay_addr_count_ok + relay_addr_count_nok) < host_addr_count));) {
+ if (!self->is_started || !self->is_active) {
+ TSK_DEBUG_INFO("ICE context stopped/cancelled while gathering TURN candidates");
+ goto bail;
+ }
+
+ u_t0 = tsk_time_now();
+ tsk_condwait_timedwait(self->turn.condwait, rto);
+ u_t1 = tsk_time_now();
+ if ((u_t1 - u_t0) >= rto) {
+ // timedwait() -> timedout
+ rto <<= 1;
+ ++i;
+ }
+
+ // count the number of TURN sessions with alloc() = ok/nok and ignore ones without response
+ relay_addr_count_ok = 0;
+ tsk_list_foreach(item, candidates_local_copy) {
+ if (!(candidate = item->data) || !candidate->turn.ss) {
+ continue;
+ }
+ if ((ret = tnet_turn_session_get_state_alloc(candidate->turn.ss, &e_tunrn_state))) {
+ goto bail;
+ }
+ if (e_tunrn_state == tnet_stun_state_ok) {
+ ++relay_addr_count_ok;
+ }
+ else if (e_tunrn_state == tnet_stun_state_nok) {
+ TSK_OBJECT_SAFE_FREE(candidate->turn.ss); // delete the session
+ ++relay_addr_count_nok;
+ }
+ }
+ }
+
+ // add/delete TURN candidates
+ tsk_list_foreach(item, candidates_local_copy) {
+ if (!(candidate = item->data) || !candidate->turn.ss) {
+ continue;
+ }
+ if ((ret = tnet_turn_session_get_state_alloc(candidate->turn.ss, &e_tunrn_state))) {
+ goto bail;
+ }
+ if (e_tunrn_state == tnet_stun_state_ok) {
+ static tsk_bool_t __b_ipv6;
+ char* foundation = tsk_null;
+ char* relay_addr = tsk_null;
+ tnet_port_t relay_port;
+ tnet_ice_candidate_t* new_cand = tsk_null;
+ struct tnet_socket_s* p_lcl_sock = tsk_null;
+
+ if ((ret = tnet_turn_session_get_relayed_addr(candidate->turn.ss, &relay_addr, &relay_port, &__b_ipv6))) {
+ goto bail;
+ }
+ if (tsk_striequals(candidate->connection_addr, relay_addr) && candidate->port == relay_port) {
+ TSK_DEBUG_INFO("Skipping redundant candidate address=%s and port=%d", relay_addr, relay_port);
+ TSK_FREE(relay_addr);
+ continue;
+ }
+ if ((ret = tnet_turn_session_get_socket_local(candidate->turn.ss, &p_lcl_sock))) {
+ goto bail;
+ }
+ tsk_strcat_2(&foundation, "%s%s", TNET_ICE_CANDIDATE_TYPE_RELAY, (const char*)candidate->foundation);
+ new_cand = tnet_ice_candidate_create(tnet_ice_cand_type_relay, p_lcl_sock, candidate->is_ice_jingle, candidate->is_rtp, self->is_video, self->ufrag, self->pwd, foundation);
+ TSK_FREE(foundation);
+ TSK_OBJECT_SAFE_FREE(p_lcl_sock);
+ if (new_cand) {
+ tsk_list_lock(self->candidates_local);
+ new_cand->turn.ss = candidate->turn.ss, candidate->turn.ss = tsk_null;
+ new_cand->turn.relay_addr = relay_addr, relay_addr = tsk_null;
+ new_cand->turn.relay_port = relay_port;
+ tnet_ice_candidate_set_rflx_addr(new_cand, new_cand->turn.relay_addr, new_cand->turn.relay_port);
+ tsk_list_push_descending_data(self->candidates_local, (void**)&new_cand);
+ tsk_list_unlock(self->candidates_local);
+ ++relay_addr_count_added;
+ }
+ TSK_FREE(relay_addr);
+ }
+ else {
+ TSK_OBJECT_SAFE_FREE(candidate->turn.ss);
+ }
+ }
+
+ // Try next TURN server
+ if (self->is_started && item_server && relay_addr_count_added == 0) {
+ goto next_server;
+ }
+
+bail:
+ if (self->is_started) {
+ if (ret == 0) {
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_Success);
+ }
+ else {
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_Failure);
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(ice_servers);
+ TSK_OBJECT_SAFE_FREE(candidates_local_copy);
+ return ret;
+}
+
+// GatheringRelayCandidates -> (Success) -> GatheringRelayCandidatesDone
+static int _tnet_ice_ctx_fsm_GatheringRelayCandidates_2_GatheringRelayCandidatesDone_X_Success(va_list *app)
+{
+ tnet_ice_ctx_t* self = va_arg(*app, tnet_ice_ctx_t *);
+ if (self->is_started) {
+ // Relay candidates are the last ones -> gathering is competed
+ return _tnet_ice_ctx_fsm_act(self, _fsm_action_GatheringComplet);
+ }
+ else {
+ return -1;
+ }
+}
+
+// GatheringReflexiveCandidates -> (Failure) -> Terminated
+static int _tnet_ice_ctx_fsm_GatheringRelayCandidates_2_Terminated_X_Failure(va_list *app)
+{
+ tnet_ice_ctx_t* self = va_arg(*app, tnet_ice_ctx_t *);
+ return _tnet_ice_ctx_signal_async(self, tnet_ice_event_type_gathering_relay_candidates_failed, "Gathering relay candidates failed");
+}
+
+// Any -> (Cancel) -> Started
+static int _tnet_ice_ctx_fsm_Any_2_Started_X_Cancel(va_list *app)
+{
+ tnet_ice_ctx_t* self;
+ self = va_arg(*app, tnet_ice_ctx_t *);
+
+ tsk_list_lock(self->candidates_remote);
+ tsk_list_clear_items(self->candidates_remote);
+ tsk_list_unlock(self->candidates_remote);
+
+ tsk_list_lock(self->candidates_pairs);
+ tsk_list_clear_items(self->candidates_pairs);
+ tsk_list_unlock(self->candidates_pairs);
+
+ TSK_OBJECT_SAFE_FREE(self->turn.ss_nominated_rtp);
+ TSK_OBJECT_SAFE_FREE(self->turn.ss_nominated_rtcp);
+
+ // Do not clear local candidates because then will be used as fallback if the remote peer is an ICE-lite
+ // These candidates will be cleared before the next local gathering
+ // tsk_list_lock(self->candidates_local);
+ // tsk_list_clear_items(self->candidates_local);
+ // tsk_list_unlock(self->candidates_local);
+
+ // restore "is_cancelled" until next cancel
+ // set "is_active" to false to allow ICE re-start
+ // self->is_cancelled = tsk_false;
+ // self->is_active = tsk_false;
+
+ // alert user
+ _tnet_ice_ctx_signal_async(self, tnet_ice_event_type_cancelled, "Cancelled");
+
+ return 0;
+
+}
+
+// Any -> (GatheringComplet) -> GatheringCompleted
+static int _tnet_ice_ctx_fsm_Any_2_GatheringCompleted_X_GatheringComplet(va_list *app)
+{
+ int ret = 0;
+ tnet_ice_ctx_t* self;
+ tsk_bool_t has_remote_candidates;
+
+ self = va_arg(*app, tnet_ice_ctx_t *);
+
+ // alert user
+ _tnet_ice_ctx_signal_async(self, tnet_ice_event_type_gathering_completed, "Gathering candidates completed");
+
+ if (self->is_started){
+ tsk_list_lock(self->candidates_remote);
+ has_remote_candidates = !TSK_LIST_IS_EMPTY(self->candidates_remote);
+ tsk_list_unlock(self->candidates_remote);
+
+ if (has_remote_candidates){
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_ConnCheck);
+ }
+ }
+ else{
+ return -1;
+ }
+
+ return ret;
+}
+
+// GatheringComplet -> (ConnCheck) -> ConnChecking
+static int _tnet_ice_ctx_fsm_GatheringCompleted_2_ConnChecking_X_ConnCheck(va_list *app)
+{
+ // Implements:
+ // 5.8. Scheduling Checks
+#if !defined(FD_SETSIZE)
+#define FD_SETSIZE 64
+#endif
+ int ret, err;
+ const tsk_list_item_t *item;
+ tnet_ice_ctx_t* self;
+ tnet_fd_t fds[FD_SETSIZE] = { -1 };
+ tnet_fd_t fds_turn[FD_SETSIZE] = { -1 };
+ uint16_t fds_count = 0, fds_turn_count = 0, k;
+ tnet_fd_t fd_max = -1;
+ fd_set set;
+ const tnet_ice_pair_t *pair;
+ struct timeval tv;
+ static const long rto = 160; // milliseconds
+ struct sockaddr_storage remote_addr;
+ uint64_t time_start, time_curr = 0, time_end = 0, concheck_timeout = 0;
+ tsk_bool_t role_conflict, restart_conneck, check_rtcp, isset, got_hosts;
+ void* recvfrom_buff_ptr = tsk_null;
+ tsk_size_t recvfrom_buff_size = 0, tries_count = 0, tries_count_min = kIceConnCheckMinTriesMin;
+ enum tnet_stun_state_e e_state;
+
+ self = va_arg(*app, tnet_ice_ctx_t *);
+
+ self->is_connchecking = tsk_true;
+
+ // "tries_count" and "tries_count_min"
+ // The connection checks to to the "relay", "prflx", "srflx" and "host" candidates are sent at the same time.
+ // Because the requests are sent at the same time it's possible to have success check for "relay" (or "srflx") candidates before the "host" candidates.
+ // "tries_count_min" is the minimum (if success check is not for "host" candidates) tries before giving up.
+ // The pairs are already sorted ("host"->"srflx"->"prflx", "relay") to make sure to choose the best candidates when there are more than one success conncheck.
+
+start_conneck:
+ role_conflict = tsk_false;
+ restart_conneck = tsk_false;
+
+ tsk_list_lock(self->candidates_pairs);
+ tsk_list_clear_items(self->candidates_pairs);
+ tsk_list_unlock(self->candidates_pairs);
+
+ TSK_OBJECT_SAFE_FREE(self->turn.ss_nominated_rtp);
+ TSK_OBJECT_SAFE_FREE(self->turn.ss_nominated_rtcp);
+
+ if ((ret = _tnet_ice_ctx_build_pairs(self, self->candidates_local, self->candidates_remote, self->candidates_pairs, self->is_controlling, self->tie_breaker, self->is_ice_jingle, self->use_rtcpmux))) {
+ TSK_DEBUG_ERROR("_tnet_ice_ctx_build_pairs() failed");
+ goto bail;
+ }
+
+#define _FD_ISSET(_fds, _fds_count, _fd, _isset) { uint16_t __i; *_isset = 0; for (__i = 0; __i < _fds_count; ++__i) { if (_fds[__i] == _fd) { *_isset = 1; break; } } }
+
+ // load fds for both rtp and rtcp sockets / create TURN permissions
+ tsk_list_lock(self->candidates_pairs);
+ tsk_list_foreach(item, self->candidates_pairs){
+ if (!(pair = item->data) || !pair->candidate_offer || !pair->candidate_offer->socket){
+ continue;
+ }
+
+ if ((fds_count < sizeof(fds) / sizeof(fds[0])) && pair->candidate_offer->socket) {
+ if (pair->candidate_offer->turn.ss && (ret = tnet_turn_session_get_state_createperm(pair->candidate_offer->turn.ss, pair->turn_peer_id, &e_state)) == 0) {
+ if (e_state == tnet_stun_state_none) {
+ ret = tnet_turn_session_createpermission(((tnet_ice_pair_t *)pair)->candidate_offer->turn.ss, pair->candidate_answer->connection_addr, pair->candidate_answer->port, &((tnet_ice_pair_t *)pair)->turn_peer_id);
+ if (ret) {
+ continue;
+ // goto bail;
+ }
+ }
+ fds_turn[fds_turn_count++] = pair->candidate_offer->socket->fd;
+ // When TURN is active the socket (host) is pulled in the TURN session and any incoming data will be forwarded to us.
+ // Do not add fd to the set
+ continue;
+ }
+ _FD_ISSET(fds, fds_count, pair->candidate_offer->socket->fd, &isset); // not in the set -> to avoid doubloon
+ if (!isset) {
+ _FD_ISSET(fds_turn, fds_turn_count, pair->candidate_offer->socket->fd, &isset); // not already managed by a TURN session
+ if (!isset) {
+ fds[fds_count++] = pair->candidate_offer->socket->fd;
+ if (pair->candidate_offer->socket->fd > fd_max) {
+ fd_max = pair->candidate_offer->socket->fd;
+ }
+ }
+ }
+ }
+ }
+ tsk_list_unlock(self->candidates_pairs);
+
+ concheck_timeout = self->concheck_timeout;
+ time_start = time_curr = tsk_time_now();
+ time_end = (time_start + concheck_timeout);
+ tries_count_min = fds_turn_count > 0 ? kIceConnCheckMinTriesMax : kIceConnCheckMinTriesMin;
+
+ while (self->is_started && self->is_active && (time_curr < time_end) && !self->have_nominated_symetric) {
+ tv.tv_sec = 0;
+ tv.tv_usec = (rto * 1000);
+
+ FD_ZERO(&set);
+ for (k = 0; k < fds_count; ++k) {
+ FD_SET(fds[k], &set);
+ }
+
+ // set new current time here to avoid "continue" skips
+ // ignore already ellapsed time if new timeout value is defined
+ time_curr = tsk_time_now();
+ if (self->concheck_timeout != concheck_timeout) {
+ concheck_timeout = self->concheck_timeout;
+ time_start = time_curr;
+ time_end = (time_start + concheck_timeout);
+ }
+
+ // Send ConnCheck requests
+ // the pairs are already sorted by priority (from high to low)
+ if (!self->have_nominated_symetric) {
+ tsk_list_foreach(item, self->candidates_pairs) {
+ if (!(pair = item->data) || !pair->candidate_offer || !pair->candidate_offer->socket) {
+ continue;
+ }
+ switch (pair->state_offer) {
+ case tnet_ice_pair_state_failed:
+ case tnet_ice_pair_state_succeed:
+ continue;
+ default: break;
+ }
+
+ ret = tnet_ice_pair_send_conncheck((tnet_ice_pair_t *)pair);
+ }
+ }
+
+ if (fds_count == 0) {
+ tsk_thread_sleep(10);
+ goto check_nomination;
+ }
+
+ if ((ret = select(fd_max + 1, &set, NULL, NULL, &tv)) < 0) {
+ TNET_PRINT_LAST_ERROR("select() failed");
+ goto bail;
+ }
+ else if (ret == 0) {
+ // timeout
+ // TSK_DEBUG_INFO("STUN request timedout");
+ goto check_nomination; //!\ continue == possible endless loop
+ }
+ else if (ret > 0) {
+ // there is data to read
+ for (k = 0; k < fds_count; ++k) {
+ tnet_fd_t fd = fds[k];
+ unsigned int len = 0;
+ tsk_size_t read = 0;
+
+ if (!FD_ISSET(fd, &set)) {
+ continue;
+ }
+
+ // Check how many bytes are pending
+ if ((ret = tnet_ioctlt(fd, FIONREAD, &len)) < 0) {
+ continue;
+ }
+
+ if (len == 0){
+ // TSK_DEBUG_INFO("tnet_ioctlt() returent zero bytes");
+ continue;
+ }
+
+ // Receive pending data
+ if (recvfrom_buff_size < len){
+ if (!(recvfrom_buff_ptr = tsk_realloc(recvfrom_buff_ptr, len))){
+ recvfrom_buff_size = 0;
+ goto bail;
+ }
+ recvfrom_buff_size = len;
+ }
+
+ // receive all messages
+ while (self->is_started && self->is_active && read < len && ret == 0) {
+ if ((ret = tnet_sockfd_recvfrom(fd, recvfrom_buff_ptr, recvfrom_buff_size, 0, (struct sockaddr *)&remote_addr)) < 0) {
+ err = tnet_geterrno();
+ /* "EAGAIN" means no data to read. We must trust "EAGAIN" instead of "read" because pending data could be removed by the system
+ */
+ /* "WSAECONNRESET"
+ The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket as it is no longer usable. On a UDP-datagram socket, this error would indicate that a previous send operation resulted in an ICMP "Port Unreachable" message.
+ */
+ if (err == TNET_ERROR_EAGAIN || err == TNET_ERROR_CONNRESET) {
+ // TODO: remove "fd" from the list if "E_CONNRESET"
+ len = 0;
+ continue;
+ }
+
+ TNET_PRINT_LAST_ERROR("Receiving STUN dgrams failed with errno=%d", err);
+ goto bail;
+ }
+
+ read += ret;
+
+ // recv() STUN message (request / response)
+ ret = tnet_ice_ctx_recv_stun_message(self, recvfrom_buff_ptr, (tsk_size_t)ret, fd, &remote_addr, &role_conflict);
+ if (ret == 0 && role_conflict) {
+ // A change in roles will require to recompute pair priorities
+ restart_conneck = tsk_true;
+ // do not break the loop -> read/process all pending STUN messages
+ }
+ }
+ }
+ }
+
+ check_nomination:
+ // check whether we need to re-start connection checking
+ if (restart_conneck) {
+ goto start_conneck;
+ }
+
+ check_rtcp = (self->use_rtcp && !self->use_rtcpmux);
+ if (!self->have_nominated_offer) {
+ self->have_nominated_offer = tnet_ice_pairs_have_nominated_offer(self->candidates_pairs, check_rtcp);
+ }
+ if (!self->have_nominated_answer) {
+ self->have_nominated_answer = tnet_ice_pairs_have_nominated_answer(self->candidates_pairs, check_rtcp);
+ }
+ if (self->have_nominated_offer && self->have_nominated_answer) {
+ self->have_nominated_symetric = tnet_ice_pairs_have_nominated_symetric_2(self->candidates_pairs, check_rtcp, &got_hosts);
+ self->have_nominated_symetric &= (got_hosts || ((tries_count++) >= tries_count_min));
+ }
+ } // while (self->is_started...
+
+ // "ret" could be "<>0" if last function used was "select()", "recvfrom()", "ioctlt()"...this is why we set the value to #0.
+ // if there was an error then, we'll jump to "bail:" and next code is skipped
+ ret = 0;
+
+bail:
+ // move to the next state depending on the conncheck result
+ if (self->is_started) {
+ if (ret == 0 && self->have_nominated_symetric) {
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_Success);
+ }
+ else {
+ if (time_curr >= time_end) {
+ TSK_DEBUG_ERROR("ConnCheck timedout, have_nominated_symetric=%s, have_nominated_answer=%s, have_nominated_offer=%s",
+ self->have_nominated_symetric ? "yes" : "false",
+ self->have_nominated_answer ? "yes" : "false",
+ self->have_nominated_offer ? "yes" : "false");
+ }
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_Failure);
+ }
+ }
+
+ TSK_FREE(recvfrom_buff_ptr);
+
+ self->is_connchecking = tsk_false;
+
+ return ret;
+}
+
+// ConnChecking -> (Success) -> ConnCheckingCompleted
+static int _tnet_ice_ctx_fsm_ConnChecking_2_ConnCheckingCompleted_X_Success(va_list *app)
+{
+ tnet_ice_ctx_t* self = va_arg(*app, tnet_ice_ctx_t *);
+ const tnet_ice_pair_t *pair_offer, *pair_answer_src, *pair_answer_dest;
+ const tsk_list_item_t *item;
+ const tnet_ice_pair_t *pair;
+ const tnet_ice_candidate_t *candidate;
+ tsk_list_t* sessions = tsk_list_create(); // for lock-free TURN sessions destroying
+ int ret;
+
+ // When destroying TURN sessions the transport is locked by shutdown()
+ // This function locks "self->candidates_pairs"
+ // TURN callback locks "self->candidates_pairs"
+ // TURN callback locks the transport
+ // => We must not lock the candidates when destroying the TURN session
+ // Test with WES8 if you want to reproduce the issue
+
+ TSK_OBJECT_SAFE_FREE(self->turn.ss_nominated_rtp);
+ TSK_OBJECT_SAFE_FREE(self->turn.ss_nominated_rtcp);
+
+ tsk_list_lock(self->candidates_pairs);
+
+ // take a reference to the negotiated TURN sessions
+ ret = tnet_ice_pairs_get_nominated_symetric_pairs(self->candidates_pairs, TNET_ICE_CANDIDATE_COMPID_RTP, &pair_offer, &pair_answer_src, &pair_answer_dest);
+ if (ret == 0) {
+ if (pair_offer && pair_offer->candidate_offer && pair_offer->candidate_offer->type_e == tnet_ice_cand_type_relay && pair_offer->candidate_offer->turn.ss) {
+ self->turn.ss_nominated_rtp = tsk_object_ref(pair_offer->candidate_offer->turn.ss);
+ self->turn.peer_id_rtp = pair_offer->turn_peer_id;
+ TSK_DEBUG_INFO("ICE: nominated TURN peer id [RTP] = %ld", self->turn.peer_id_rtp);
+ }
+ TSK_DEBUG_INFO("ICE: nominated symetric RTP pairs: offer:%llu, answer-src:%llu, answser-dest:%llu",
+ pair_offer ? pair_offer->id : 0, pair_answer_src ? pair_answer_src->id : 0, pair_answer_dest ? pair_answer_dest->id : 0);
+ }
+ if (ret == 0 && pair_offer) { ((tnet_ice_pair_t *)pair_offer)->is_nominated = tsk_true; } // "is_nominated" is used do decide whether to include "USE-CANDIDATE" attribute when aggressive mode is disabled
+
+ ret = tnet_ice_pairs_get_nominated_symetric_pairs(self->candidates_pairs, TNET_ICE_CANDIDATE_COMPID_RTCP, &pair_offer, &pair_answer_src, &pair_answer_dest);
+ if (ret == 0) {
+ if (pair_offer && pair_offer->candidate_offer && pair_offer->candidate_offer->type_e == tnet_ice_cand_type_relay && pair_offer->candidate_offer->turn.ss) {
+ self->turn.ss_nominated_rtcp = tsk_object_ref(pair_offer->candidate_offer->turn.ss);
+ self->turn.peer_id_rtcp = pair_offer->turn_peer_id;
+ TSK_DEBUG_INFO("ICE: nominated TURN peer id [RTCP] = %ld", self->turn.peer_id_rtp);
+ }
+ TSK_DEBUG_INFO("ICE: nominated symetric RTCP(use:%d, mux:%d) pairs: offer:%llu, answer-src:%llu, answser-dest:%llu",
+ self->use_rtcp ? 1 : 0, self->use_rtcpmux ? 1 : 0,
+ pair_offer ? pair_offer->id : 0, pair_answer_src ? pair_answer_src->id : 0, pair_answer_dest ? pair_answer_dest->id : 0);
+ }
+ if (ret == 0 && pair_offer) { ((tnet_ice_pair_t *)pair_offer)->is_nominated = tsk_true; } // "is_nominated" is used do decide whether to include "USE-CANDIDATE" attribute when aggressive mode is disabled
+
+ // collect all useless TURN sessions (pairs)
+ tsk_list_foreach(item, self->candidates_pairs) {
+ if (!(pair = item->data) || !pair->candidate_offer || !pair->candidate_offer->turn.ss) {
+ continue;
+ }
+ if (pair->candidate_offer->turn.ss != self->turn.ss_nominated_rtp && pair->candidate_offer->turn.ss != self->turn.ss_nominated_rtcp) {
+ tsk_list_push_back_data(sessions, (void**)&pair->candidate_offer->turn.ss);
+ TSK_OBJECT_SAFE_FREE(pair->candidate_offer->turn.ss);
+ }
+ }
+
+ tsk_list_unlock(self->candidates_pairs);
+
+ // collect all useless TURN sessions (local candidates)
+ tsk_list_lock(self->candidates_local);
+ tsk_list_foreach(item, self->candidates_local) {
+ if (!(candidate = item->data) || !candidate->turn.ss) {
+ continue;
+ }
+ if (candidate->turn.ss != self->turn.ss_nominated_rtp && candidate->turn.ss != self->turn.ss_nominated_rtcp) {
+ tsk_list_push_back_data(sessions, (void**)&candidate->turn.ss);
+ TSK_OBJECT_SAFE_FREE(((tnet_ice_candidate_t*)candidate)->turn.ss);
+ }
+ }
+ tsk_list_unlock(self->candidates_local);
+
+ // collect all useless TURN sessions (remote candidates)
+ tsk_list_lock(self->candidates_remote);
+ tsk_list_foreach(item, self->candidates_remote) {
+ if (!(candidate = item->data) || !candidate->turn.ss) {
+ continue;
+ }
+ if (candidate->turn.ss != self->turn.ss_nominated_rtp && candidate->turn.ss != self->turn.ss_nominated_rtcp) {
+ tsk_list_push_back_data(sessions, (void**)&candidate->turn.ss);
+ TSK_OBJECT_SAFE_FREE(((tnet_ice_candidate_t*)candidate)->turn.ss);
+ }
+ }
+ tsk_list_unlock(self->candidates_remote);
+
+ // lock-free destruction
+ TSK_OBJECT_SAFE_FREE(sessions);
+
+ return _tnet_ice_ctx_signal_async(self, tnet_ice_event_type_conncheck_succeed, "ConnCheck succeed");
+}
+
+// ConnChecking -> (Failure) ->Terminated
+static int _tnet_ice_ctx_fsm_ConnChecking_2_Terminated_X_Failure(va_list *app)
+{
+ tnet_ice_ctx_t* self = va_arg(*app, tnet_ice_ctx_t *);
+ return _tnet_ice_ctx_signal_async(self, tnet_ice_event_type_conncheck_failed, "ConnCheck failed");
+}
+
+// Any (AnyNotStarted) -> Terminated
+static int _tnet_ice_ctx_fsm_Any_2_Terminated_X_AnyNotStarted(va_list *app)
+{
+ return 0;
+}
+
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// == STATE MACHINE END ==
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+static int _tnet_ice_ctx_fsm_OnTerminated(tnet_ice_ctx_t* self)
+{
+ TSK_DEBUG_INFO("=== ICE CTX SM Terminated ===");
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+
+ // still started but no longer active
+ self->is_active = tsk_false;
+
+ return 0;
+}
+
+static tsk_bool_t _tnet_ice_ctx_fsm_cond_NotStarted(tnet_ice_ctx_t* self, const void* _any)
+{
+ return (!self || !self->is_started);
+}
+
+static int _tnet_ice_ctx_restart(tnet_ice_ctx_t* self)
+{
+ int ret = 0;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ ret = tsk_fsm_set_current_state(self->fsm, _fsm_state_Started);
+ ret = _tnet_ice_ctx_fsm_act(self, _fsm_action_GatherHostCandidates);
+
+ self->is_active = (ret == 0);
+ return ret;
+}
+
+static int _tnet_ice_ctx_recv_stun_message_for_pair(tnet_ice_ctx_t* self, const tnet_ice_pair_t* pair, const void* data, tsk_size_t size, tnet_fd_t local_fd, const struct sockaddr_storage* remote_addr, tsk_bool_t *role_conflict)
+{
+ tnet_stun_pkt_t* message;
+ int ret = 0;
+ if (!self || !role_conflict || !data || !size || local_fd < 0 || !remote_addr) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ *role_conflict = tsk_false;
+
+ if (!TNET_STUN_BUFF_IS_STUN2(((uint8_t*)data), size)) {
+ if (self->rtp_callback) {
+ return self->rtp_callback(self->rtp_callback_data, data, size, local_fd, remote_addr);
+ }
+ TSK_DEBUG_INFO("Not STUN message");
+ return 0;
+ }
+
+ if (!self->is_active) {
+ TSK_DEBUG_INFO("ICE context not active yet");
+ return 0;
+ }
+
+ if ((ret = tnet_stun_pkt_read(data, size, &message)) == 0 && message) {
+ if (message->e_type == tnet_stun_pkt_type_binding_request) {
+ tsk_bool_t is_local_conncheck_started;
+ if (self->is_building_pairs) {
+ TSK_DEBUG_INFO("Incoming STUN binding request while building new ICE pairs... wait for %d milliseconds max", kIcePairsBuildingTimeMax);
+ tsk_condwait_timedwait(self->condwait_pairs, kIcePairsBuildingTimeMax);
+ if (self->is_building_pairs) {
+ TSK_DEBUG_WARN("%d milliseconds ellapsed and still building pairs", kIcePairsBuildingTimeMax);
+ }
+ if (!self->is_active) {
+ TSK_DEBUG_WARN("ICE context deactivated while waiting for ICE pairs to finish building");
+ TSK_OBJECT_SAFE_FREE(message);
+ return 0;
+ }
+ }
+ is_local_conncheck_started = !TSK_LIST_IS_EMPTY(self->candidates_pairs); // if empty means local conncheck haven't started
+ if (!pair && is_local_conncheck_started) {
+ pair = tnet_ice_pairs_find_by_fd_and_addr(self->candidates_pairs, local_fd, remote_addr);
+ }
+ if (!pair && !self->have_nominated_symetric && is_local_conncheck_started){ // pair not found and we're still negotiating
+ // rfc 5245 - 7.1.3.2.1. Discovering Peer Reflexive Candidates
+ tnet_ice_pair_t* pair_peer = tnet_ice_pair_prflx_create(self->candidates_pairs, local_fd, remote_addr);
+ if (pair_peer) {
+ pair = pair_peer; // save memory address
+ tsk_list_push_descending_data(self->candidates_pairs, (void**)&pair_peer);
+ TSK_OBJECT_SAFE_FREE(pair_peer);
+ }
+ }
+ if (pair) {
+ short resp_code = 0;
+ char* resp_phrase = tsk_null;
+ // authenticate the request
+ tnet_ice_pair_auth_conncheck(pair, message, data, size, &resp_code, &resp_phrase);
+ if (resp_code > 0 && resp_phrase){
+ if (resp_code >= 200 && resp_code <= 299){
+ // Before sending the success response check that there are no role conflict
+ if (self->is_controlling){ // I'm ICE-CONTROLLING
+ const tnet_stun_attr_vdata_t* stun_att_ice_controlling;
+ if ((ret = tnet_stun_pkt_attr_find_first(message, tnet_stun_attr_type_ice_controlling, (const tnet_stun_attr_t**)&stun_att_ice_controlling)) == 0 && stun_att_ice_controlling){
+ TSK_DEBUG_WARN("Role conflicts (SEND)");
+ if (self->tie_breaker >= *((uint64_t*)stun_att_ice_controlling->p_data_ptr)) {
+ resp_code = kStunErrCodeIceConflict;
+ tsk_strupdate(&resp_phrase, "Role conflicts");
+ }
+ else {
+ // switch to "controlled" role
+ self->is_controlling = tsk_false;
+ *role_conflict = tsk_true;
+ }
+ }
+ else;
+ }
+ else { // I'm ICE-CONTROLLED
+ const tnet_stun_attr_vdata_t* stun_att_ice_controlled;
+ if ((ret = tnet_stun_pkt_attr_find_first(message, tnet_stun_attr_type_ice_controlled, (const tnet_stun_attr_t**)&stun_att_ice_controlled)) == 0 && stun_att_ice_controlled) {
+ TSK_DEBUG_WARN("Role conflicts (SEND)");
+ if (self->tie_breaker >= *((uint64_t*)stun_att_ice_controlled->p_data_ptr)) {
+ self->is_controlling = tsk_true;
+ *role_conflict = tsk_true;
+ }
+ else {
+ resp_code = kStunErrCodeIceConflict;
+ tsk_strupdate(&resp_phrase, "Role conflicts");
+ }
+ }
+ }
+ }
+ ret = tnet_ice_pair_send_response((tnet_ice_pair_t *)pair, message, resp_code, resp_phrase, remote_addr);
+ // "keepalive": also send STUN-BINDING if we receive one in the nominated pair and conneck is finished
+ //!\ IMPORTANT: chrome requires this
+ //!\ We also need to continue sending connection checks as we don't really know if the remote party has finished checking
+ if ((self->is_ice_jingle || pair->is_nominated) && self->have_nominated_symetric) {
+ ret = tnet_ice_pair_send_conncheck((tnet_ice_pair_t *)pair); // "keepalive"
+ }
+ }
+ TSK_FREE(resp_phrase);
+ }
+ else { // if(pair == null)
+ if (!is_local_conncheck_started) {
+ TSK_DEBUG_INFO("ICE local conncheck haven't started yet");
+ }
+ else {
+ TSK_DEBUG_ERROR("Cannot find ICE pair with local fd = %d", local_fd);
+ }
+ }
+ }
+ else if (TNET_STUN_PKT_IS_RESP(message)) {
+ if (pair || (pair = tnet_ice_pairs_find_by_response(self->candidates_pairs, message))) {
+ ret = tnet_ice_pair_recv_response(((tnet_ice_pair_t*)pair), message, self->is_connchecking);
+#if 0
+ if (TNET_STUN_PKT_RESP_IS_ERROR(message)) {
+ uint16_t u_code;
+ if ((ret = tnet_stun_pkt_get_errorcode(message, &u_code)) == 0 && u_code == kStunErrCodeIceConflict) {
+ // If this code is called this means that we have lower tie-breaker and we must toggle our role
+ TSK_DEBUG_WARN("Role conflicts (RECV)");
+ self->is_controlling = !self->is_controlling;
+ *role_conflict = tsk_true;
+ }
+ }
+#endif
+ }
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(message);
+
+ return ret;
+}
+
+static int _tnet_ice_ctx_send_turn_raw(struct tnet_ice_ctx_s* self, struct tnet_turn_session_s* turn_ss, tnet_turn_peer_id_t turn_peer_id, const void* data, tsk_size_t size)
+{
+ if (!self || !turn_ss || !data || !size){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ // (self);
+ return tnet_turn_session_send_data(turn_ss, turn_peer_id, data, (uint16_t)size);
+}
+
+
+// build pairs as per RFC 5245 section "5.7.1. Forming Candidate Pairs"
+static int _tnet_ice_ctx_build_pairs(struct tnet_ice_ctx_s* self, tnet_ice_candidates_L_t* local_candidates, tnet_ice_candidates_L_t* remote_candidates, tnet_ice_pairs_L_t* result_pairs, tsk_bool_t is_controlling, uint64_t tie_breaker, tsk_bool_t is_ice_jingle, tsk_bool_t is_rtcpmuxed)
+{
+ const tsk_list_item_t *item_local, *item_remote;
+ const tnet_ice_candidate_t *cand_local, *cand_remote;
+ tnet_ice_pair_t *pair;
+ enum tnet_turn_transport_e e_req_transport;
+ tnet_family_t addr_family_local, addr_family_remote;
+
+ if (!self || TSK_LIST_IS_EMPTY(local_candidates) || TSK_LIST_IS_EMPTY(remote_candidates) || !result_pairs) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ self->is_building_pairs = tsk_true;
+ TSK_DEBUG_INFO("ICE: begin building pairs(is_rtcpmuxed=%d)", is_rtcpmuxed);
+
+ tsk_list_clear_items(result_pairs);
+
+ tsk_list_lock(local_candidates);
+ tsk_list_lock(remote_candidates);
+ tsk_list_lock(result_pairs);
+
+ tsk_list_foreach(item_local, local_candidates) {
+ if (!(cand_local = item_local->data)) {
+ continue;
+ }
+ if (is_rtcpmuxed && cand_local->comp_id == TNET_ICE_CANDIDATE_COMPID_RTCP) {
+ continue;
+ }
+#if 0 // TURN:FORCE
+ if (cand_local->type_e != tnet_ice_cand_type_relay) {
+ continue;
+ }
+#endif
+
+ tsk_list_foreach(item_remote, remote_candidates) {
+ if (!(cand_remote = item_remote->data)) {
+ continue;
+ }
+ // Hack for Chrome bug (candidate with port=zero) to avoid printing errors.
+ if (cand_remote->port == 0) {
+ TSK_DEBUG_INFO("Skipping remote ICE candidate with port = 0");
+ continue;
+ }
+
+ // CompIds(1=RTP, 2=RTCP) must match
+ if ((cand_remote->comp_id != cand_local->comp_id)){
+ continue;
+ }
+ // IP versions must match. Cannot use IPv4 socket to send/recv to IPv6 address.
+ if (cand_local->socket) {
+ addr_family_local = TNET_SOCKET_TYPE_IS_IPV4(cand_local->socket->type) ? AF_INET : AF_INET6;
+ addr_family_remote = tnet_get_family(cand_remote->connection_addr, cand_remote->port);
+ if (addr_family_local != addr_family_remote) {
+ TSK_DEBUG_INFO("Address family mismatch:%d<->%d", addr_family_local, addr_family_remote);
+ continue;
+ }
+ }
+ if (cand_local->turn.ss) {
+ if (tnet_turn_session_get_req_transport(cand_local->turn.ss, &e_req_transport) != 0) {
+ continue;
+ }
+ if (e_req_transport == tnet_turn_transport_udp && !TNET_SOCKET_TYPE_IS_DGRAM(cand_remote->transport_e)) {
+ continue;
+ }
+ if (e_req_transport == tnet_turn_transport_tcp && !TNET_SOCKET_TYPE_IS_STREAM(cand_remote->transport_e)) {
+ continue;
+ }
+ }
+ else {
+ if (cand_remote->transport_e != cand_local->transport_e) {
+ continue;
+ }
+ }
+
+ if ((pair = tnet_ice_pair_create(cand_local, cand_remote, is_controlling, tie_breaker, is_ice_jingle))) {
+ TSK_DEBUG_INFO("ICE Pair(%llu, %llu): [%s %u %u %s %d] -> [%s %u %u %s %d]",
+ pair->id,
+ pair->priority,
+
+ cand_local->foundation,
+ cand_local->priority,
+ cand_local->comp_id,
+ cand_local->connection_addr,
+ cand_local->port,
+
+ cand_remote->foundation,
+ cand_remote->priority,
+ cand_remote->comp_id,
+ cand_remote->connection_addr,
+ cand_remote->port);
+ tsk_list_push_descending_data(result_pairs, (void**)&pair);
+ }
+ }
+ }
+#if 0
+ tsk_list_foreach(item_local, result_pairs) {
+ if (!(pair = item_local->data)) {
+ continue;
+ }
+
+ TSK_DEBUG_INFO("ICE Pair(%llu, %llu): [%s %u %s %d] -> [%s %u %s %d]",
+ pair->id,
+ pair->priority,
+
+ pair->candidate_offer->foundation,
+ pair->candidate_offer->comp_id,
+ pair->candidate_offer->connection_addr,
+ pair->candidate_offer->port,
+
+ pair->candidate_answer->foundation,
+ pair->candidate_answer->comp_id,
+ pair->candidate_answer->connection_addr,
+ pair->candidate_answer->port);
+ }
+#endif
+
+ tsk_list_unlock(local_candidates);
+ tsk_list_unlock(remote_candidates);
+ tsk_list_unlock(result_pairs);
+
+ self->is_building_pairs = tsk_false;
+ tsk_condwait_broadcast(self->condwait_pairs);
+ TSK_DEBUG_INFO("ICE: end building pairs");
+
+ return 0;
+}
+
+
+static int _tnet_ice_ctx_fsm_act(tnet_ice_ctx_t* self, tsk_fsm_action_id action_id)
+{
+ tnet_ice_action_t *action = tsk_null;
+ tnet_ice_event_t* e = tsk_null;
+ static const char* phrase = "$action$";
+ int ret = 0;
+
+ if (!self || !self->fsm){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!(action = tnet_ice_action_create(action_id))){
+ TSK_DEBUG_ERROR("Failed to create action");
+ return -2;
+ }
+
+ if (self->is_sync_mode) {
+ ret = tsk_fsm_act(self->fsm, action->id, self, action, self, action);
+ }
+ else {
+ if ((e = tnet_ice_event_create(self, tnet_ice_event_type_action, phrase, self->userdata))){
+ tnet_ice_event_set_action(e, action);
+ TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(self), e);
+ goto bail;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create ICE event");
+ ret = -2;
+ goto bail;
+ }
+ }
+
+bail:
+ TSK_OBJECT_SAFE_FREE(e);
+ TSK_OBJECT_SAFE_FREE(action);
+ return ret;
+}
+
+static int _tnet_ice_ctx_signal_async(tnet_ice_ctx_t* self, tnet_ice_event_type_t type, const char* phrase)
+{
+ tnet_ice_event_t* e;
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (self->is_silent_mode && type != tnet_ice_event_type_action) { // silent mode ON and not action to move the FSM
+ TSK_DEBUG_INFO("ICE silent mode ON...to not notify '%d:%s'", type, phrase);
+ return 0;
+ }
+
+ if ((e = tnet_ice_event_create(self, type, phrase, self->userdata))){
+ TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(self), e);
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create ICE event");
+ return -2;
+ }
+}
+
+static int _tnet_ice_ctx_turn_callback(const struct tnet_turn_session_event_xs *e)
+{
+ tnet_ice_ctx_t *ctx = tsk_object_ref(TSK_OBJECT(e->pc_usr_data));
+ struct tnet_turn_session_s* session = tsk_object_ref(TSK_OBJECT(e->pc_session));
+ int ret = 0;
+
+ if (!ctx) {
+ // the ICE context is being destroyed but TURN session not freed yet
+ goto bail;
+ }
+
+ switch (e->e_type) {
+ case tnet_turn_session_event_type_alloc_ok:
+ case tnet_turn_session_event_type_refresh_ok:
+ case tnet_turn_session_event_type_chanbind_ok:
+ case tnet_turn_session_event_type_connect_ok:
+ default:
+ {
+ break;
+ }
+
+ case tnet_turn_session_event_type_alloc_nok:
+ case tnet_turn_session_event_type_refresh_nok:
+ case tnet_turn_session_event_type_perm_nok:
+ case tnet_turn_session_event_type_chanbind_nok:
+ case tnet_turn_session_event_type_connect_nok:
+ {
+ // Do not raise error event if no nominated candidate because
+ // TURN error could be raised by the session when we're in "conncheck" state and this is a normal case.
+ if (ctx->is_active && ctx->is_started && ctx->turn.ss_nominated_rtp && ctx->turn.peer_id_rtp == e->u_peer_id) {
+ TSK_DEBUG_ERROR("TURN connection broken (peer-id=%ld)", e->u_peer_id);
+ if ((ret = _tnet_ice_ctx_signal_async(ctx, tnet_ice_event_type_turn_connection_broken, "TURN connection is broken"))) {
+ goto bail;
+ }
+ }
+ break;
+ }
+
+ case tnet_turn_session_event_type_perm_ok:
+ {
+ enum tnet_turn_transport_e e_req_transport;
+ if ((ret = tnet_turn_session_get_req_transport(session, &e_req_transport))) {
+ goto bail;
+ }
+
+ if (e_req_transport == tnet_turn_transport_tcp) {
+ // TCP-Connect: rfc6062 - 4.3. Initiating a Connection
+ if ((ret = tnet_turn_session_connect(session, e->u_peer_id))) {
+ goto bail;
+ }
+ }
+ else {
+ // Bind a channel (not required). If succeed, will be used to save bandwidth usage.
+ // TODO: should be done only if first "get_state(chanbind)==none". Not an issue, if it already exists then, will be refreshed.
+ if ((ret = tnet_turn_session_chanbind(session, e->u_peer_id))) {
+ goto bail;
+ }
+ }
+ break;
+ }
+
+ case tnet_turn_session_event_type_recv_data:
+ {
+ tsk_bool_t role_conflict;
+ tnet_ice_pair_t* pair = tsk_null;
+ if (e->u_peer_id != kTurnPeerIdInvalid) {
+ const tsk_list_item_t *item;
+ tsk_list_lock(ctx->candidates_pairs);
+ tsk_list_foreach(item, ctx->candidates_pairs) {
+ if (((const tnet_ice_pair_t*)item->data)->turn_peer_id == e->u_peer_id) {
+ pair = tsk_object_ref((void*)item->data);
+ break;
+ }
+ }
+ tsk_list_unlock(ctx->candidates_pairs);
+ }
+
+ ret = _tnet_ice_ctx_recv_stun_message_for_pair(
+ ctx,
+ pair,
+ e->data.pc_data_ptr, e->data.u_data_size,
+ e->pc_enet ? e->pc_enet->local_fd : TNET_INVALID_FD,
+ e->pc_enet ? &e->pc_enet->remote_addr : tsk_null,
+ &role_conflict);
+ TSK_OBJECT_SAFE_FREE(pair);
+ if (ret) {
+ goto bail;
+ }
+
+ // rebuild candidates if role conflict
+ if (role_conflict) {
+ tsk_list_lock(ctx->candidates_pairs);
+ tsk_list_clear_items(ctx->candidates_pairs);
+ tsk_list_unlock(ctx->candidates_pairs);
+
+ TSK_OBJECT_SAFE_FREE(ctx->turn.ss_nominated_rtp);
+ TSK_OBJECT_SAFE_FREE(ctx->turn.ss_nominated_rtcp);
+
+ if ((ret = _tnet_ice_ctx_build_pairs(ctx, ctx->candidates_local, ctx->candidates_remote, ctx->candidates_pairs, ctx->is_controlling, ctx->tie_breaker, ctx->is_ice_jingle, ctx->use_rtcpmux))) {
+ TSK_DEBUG_ERROR("_tnet_ice_ctx_build_pairs() failed");
+ goto bail;
+ }
+ }
+
+ break;
+ }
+ }
+
+ // alert() waiting threads
+ if ((ret = tsk_condwait_broadcast(ctx->turn.condwait))) {
+ goto bail;
+ }
+
+bail:
+ tsk_object_unref(ctx);
+ tsk_object_unref(session);
+ return ret;
+}
+
+static void* TSK_STDCALL _tnet_ice_ctx_run(void* self)
+{
+ // No need to take ref(ctx) because this thread will be stopped by the dtor() before memory free.
+ tsk_list_item_t *curr;
+ tnet_ice_ctx_t *ctx = (tnet_ice_ctx_t *)(self);
+ tnet_ice_event_t *e;
+
+ TSK_DEBUG_INFO("ICE CTX::run -- START");
+
+ TSK_RUNNABLE_RUN_BEGIN(ctx);
+
+ // must because "ctx->callback(e);" could call a function trying to free "ctx"
+ // do not move before "TSK_RUNNABLE_RUN_BEGIN(ctx)", otherwise it'll be required to stop the "runnable" to have "ctx->refCount==0"
+ ctx = tsk_object_ref(ctx);
+
+ if (ctx->is_started && (curr = TSK_RUNNABLE_POP_FIRST(ctx))) {
+ e = (tnet_ice_event_t*)curr->data;
+ switch (e->type) {
+ case tnet_ice_event_type_action:
+ {
+ if (e->action) {
+ tsk_fsm_act(ctx->fsm, e->action->id, ctx, e->action, ctx, e->action);
+ }
+ break;
+ }
+ default:
+ {
+ if (ctx->callback){
+ ctx->callback(e);
+ }
+ break;
+ }
+ }
+ tsk_object_unref(curr);
+ }
+
+ if (!(ctx = tsk_object_unref(ctx))) {
+ goto exit;
+ }
+
+ TSK_RUNNABLE_RUN_END(ctx);
+
+exit:
+ if (ctx) {
+ tsk_list_clear_items(ctx->candidates_local);
+ tsk_list_clear_items(ctx->candidates_remote);
+ tsk_list_lock(ctx->candidates_pairs); // must
+ tsk_list_clear_items(ctx->candidates_pairs);
+ tsk_list_unlock(ctx->candidates_pairs);
+ }
+
+ TSK_DEBUG_INFO("ICE CTX::run -- STOP");
+
+ return 0;
+}
+
+static int _tnet_ice_ctx_servers_clear(struct tnet_ice_ctx_s* self)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_list_lock(self->servers);
+ tsk_list_clear_items(self->servers);
+ tsk_list_unlock(self->servers);
+ return 0;
+}
+
+static int _tnet_ice_ctx_server_add(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto,
+ enum tnet_socket_type_e e_transport,
+ const char* str_server_addr, uint16_t u_server_port,
+ const char* str_software,
+ const char* str_username, const char* str_password)
+{
+ struct tnet_ice_server_s* ice_server;
+ int ret = -1;
+ if (!self || !e_proto || !str_server_addr || !u_server_port) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // TURN requires credentials
+ if ((e_proto & tnet_ice_server_proto_turn) == tnet_ice_server_proto_turn && (tsk_strnullORempty(str_username) || tsk_strnullORempty(str_password))) {
+ /* rfc5766 - 4. General Behavior
+ The server MUST demand that all requests from the client
+ be authenticated using this mechanism, or that a equally strong or
+ stronger mechanism for client authentication is used.*/
+ TSK_DEBUG_ERROR("TURN requires credentials");
+ return -1;
+ }
+ // Create and add the ICE server
+ tsk_list_lock(self->servers);
+ if (_tnet_ice_ctx_server_exists(self, e_proto, e_transport, str_server_addr, u_server_port)) {
+ TSK_DEBUG_WARN("ICE server (proto=%d, transport=%d, addr=%s, port=%hu) already exists", e_proto, e_transport, str_server_addr, u_server_port);
+ ret = 0; // Not an error
+ goto bail;
+ }
+ if (!(ice_server = tnet_ice_server_create(e_proto, e_transport, str_server_addr, u_server_port, str_software, str_username, str_password))) {
+ TSK_DEBUG_ERROR("Failed to create ICE server(proto=%d, transport=%d, addr=%s, port=%hu)", e_proto, e_transport, str_server_addr, u_server_port);
+ goto bail;
+ }
+ tsk_list_push_back_data(self->servers, (void**)&ice_server);
+ TSK_OBJECT_SAFE_FREE(ice_server);
+
+ ret = 0;
+bail:
+ tsk_list_unlock(self->servers);
+ return ret;
+}
+
+static int _tnet_ice_ctx_server_remove(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto, enum tnet_socket_type_e e_transport, const char* str_server_addr, uint16_t u_server_port)
+{
+ const struct tnet_ice_server_s* _pc_ice_srv;
+ const tsk_list_item_t *pc_item;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_list_lock(self->servers);
+ tsk_list_foreach(pc_item, self->servers) {
+ if ((_pc_ice_srv = pc_item->data)) {
+ if (_pc_ice_srv->e_proto == e_proto && _pc_ice_srv->e_transport == e_transport && _pc_ice_srv->u_server_port == u_server_port && tsk_striequals(_pc_ice_srv->str_server_addr, str_server_addr)) {
+ tsk_list_remove_item(self->servers, (tsk_list_item_t *)pc_item);
+ break;
+ }
+ }
+ }
+ tsk_list_unlock(self->servers);
+ return 0;
+}
+
+static const struct tnet_ice_server_s* _tnet_ice_ctx_server_find(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto, enum tnet_socket_type_e e_transport, const char* str_server_addr, uint16_t u_server_port)
+{
+ const struct tnet_ice_server_s* pc_ice_srv = tsk_null;
+ const struct tnet_ice_server_s* _pc_ice_srv;
+ const tsk_list_item_t *pc_item;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+ tsk_list_lock(self->servers);
+ tsk_list_foreach(pc_item, self->servers) {
+ if ((_pc_ice_srv = pc_item->data)) {
+ if (_pc_ice_srv->e_proto == e_proto && _pc_ice_srv->e_transport == e_transport && _pc_ice_srv->u_server_port == u_server_port && tsk_striequals(_pc_ice_srv->str_server_addr, str_server_addr)) {
+ pc_ice_srv = _pc_ice_srv;
+ break;
+ }
+ }
+ }
+ tsk_list_unlock(self->servers);
+ return pc_ice_srv;
+}
+
+static tsk_bool_t _tnet_ice_ctx_server_exists(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto, enum tnet_socket_type_e e_transport, const char* str_server_addr, uint16_t u_server_port)
+{
+ return _tnet_ice_ctx_server_find(self, e_proto, e_transport, str_server_addr, u_server_port) ? tsk_true : tsk_false;
+}
+
+static tsk_size_t _tnet_ice_ctx_servers_count_by_proto(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto)
+{
+ tsk_size_t count = 0;
+ if (self) {
+ const struct tnet_ice_server_s* _pc_ice_srv;
+ const tsk_list_item_t *pc_item;
+ tsk_list_lock(self->servers);
+ tsk_list_foreach(pc_item, self->servers) {
+ if ((_pc_ice_srv = pc_item->data) && (_pc_ice_srv->e_proto & e_proto) == e_proto) {
+ ++count;
+ }
+ }
+ tsk_list_unlock(self->servers);
+ }
+ return count;
+}
+
+// Up to the caller to free the returned list
+static tnet_ice_servers_L_t* _tnet_ice_ctx_servers_copy(struct tnet_ice_ctx_s* self, enum tnet_ice_server_proto_e e_proto)
+{
+ tnet_ice_servers_L_t* copy = tsk_list_create();
+ if (copy) {
+ const struct tnet_ice_server_s* _pc_ice_srv;
+ const tsk_list_item_t *pc_item;
+ tsk_list_lock(self->servers);
+ tsk_list_foreach(pc_item, self->servers) {
+ if ((_pc_ice_srv = pc_item->data) && (_pc_ice_srv->e_proto & e_proto) == e_proto) {
+ tnet_ice_server_t* srv = (tnet_ice_server_t*)tsk_object_ref(pc_item->data);
+ tsk_list_push_back_data(copy, (void**)&srv);
+ }
+ }
+ tsk_list_unlock(self->servers);
+ }
+ return copy;
+}
diff --git a/tinyNET/src/ice/tnet_ice_ctx.h b/tinyNET/src/ice/tnet_ice_ctx.h
new file mode 100644
index 0000000..015fdcf
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice_ctx.h
@@ -0,0 +1,113 @@
+/*
+* Copyright (C) 2012-2015 Doubango Telecom <http://www.doubango.org>.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_ice_ctx.h
+ * @brief Interactive Connectivity Establishment (ICE) implementation as per RFC 5245.
+ */
+
+#ifndef TNET_ICE_CTX_H
+#define TNET_ICE_CTX_H
+
+#include "tinynet_config.h"
+
+#include "tnet_types.h"
+
+#include "tsk_common.h"
+
+#if defined(_MSC_VER)
+// # pragma deprecated(tnet_ice_ctx_set_stun, tnet_ice_ctx_set_stun_enabled, tnet_ice_ctx_set_turn_enabled)
+#endif
+
+TNET_BEGIN_DECLS
+
+struct tnet_ice_event_s;
+
+typedef int (*tnet_ice_callback_f)(const struct tnet_ice_event_s *e);
+typedef int (*tnet_ice_rtp_callback_f)(const void* callback_data, const uint8_t* data_ptr, tsk_size_t data_size, tnet_fd_t local_fd, const struct sockaddr_storage* remote_addr);
+
+TINYNET_API struct tnet_ice_ctx_s* tnet_ice_ctx_create(tsk_bool_t is_ice_jingle, tsk_bool_t use_ipv6, tsk_bool_t use_rtcp, tsk_bool_t is_video, tnet_ice_callback_f callback, const void* userdata);
+TINYNET_API int tnet_ice_ctx_set_userdata(struct tnet_ice_ctx_s* self, const void* userdata);
+//@deprecated: Use "tnet_ice_ctx_add_server()"
+TNET_DEPRECATED(TINYNET_API int tnet_ice_ctx_set_stun(
+ struct tnet_ice_ctx_s* self,
+ const char* server_addr,
+ uint16_t server_port,
+ const char* software,
+ const char* username,
+ const char* password));
+TINYNET_API int tnet_ice_ctx_add_server(
+ struct tnet_ice_ctx_s* self,
+ const char* transport_proto, // "udp", "tcp", "tls", "ws", "wss"...
+ const char* server_addr,
+ uint16_t server_port,
+ tsk_bool_t use_turn,
+ tsk_bool_t use_stun,
+ const char* username,
+ const char* password);
+#define tnet_ice_ctx_add_server_turn(self, transport_proto, server_addr, server_port, username, password) \
+ tnet_ice_ctx_add_server((self), (transport_proto), (server_addr), (server_port), tsk_true/*use_turn*/, tsk_false/*use_stun*/, (username), (password))
+#define tnet_ice_ctx_add_server_stun(self, transport_proto, server_addr, server_port, username, password) \
+ tnet_ice_ctx_add_server((self), (transport_proto), (server_addr), (server_port), tsk_false/*use_turn*/, tsk_true/*use_stun*/, (username), (password))
+TINYNET_API int tnet_ice_ctx_set_sync_mode(struct tnet_ice_ctx_s* self, tsk_bool_t sync_mode);
+TINYNET_API int tnet_ice_ctx_set_silent_mode(struct tnet_ice_ctx_s* self, tsk_bool_t silent_mode);
+TINYNET_API int tnet_ice_ctx_set_stun_enabled(struct tnet_ice_ctx_s* self, tsk_bool_t stun_enabled);
+TINYNET_API int tnet_ice_ctx_set_turn_enabled(struct tnet_ice_ctx_s* self, tsk_bool_t turn_enabled);
+TINYNET_API int tnet_ice_ctx_start(struct tnet_ice_ctx_s* self);
+TINYNET_API int tnet_ice_ctx_rtp_callback(struct tnet_ice_ctx_s* self, tnet_ice_rtp_callback_f rtp_callback, const void* rtp_callback_data);
+TINYNET_API int tnet_ice_ctx_set_concheck_timeout(struct tnet_ice_ctx_s* self, int64_t timeout);
+TINYNET_API int tnet_ice_ctx_set_remote_candidates(struct tnet_ice_ctx_s* self, const char* candidates, const char* ufrag, const char* pwd, tsk_bool_t is_controlling, tsk_bool_t is_ice_jingle);
+TINYNET_API int tnet_ice_ctx_set_remote_candidates_2(struct tnet_ice_ctx_s* self, const char* candidates, const char* ufrag, const char* pwd, tsk_bool_t is_controlling, tsk_bool_t is_ice_jingle, tsk_bool_t use_rtcpmux);
+TINYNET_API int tnet_ice_ctx_set_rtcpmux(struct tnet_ice_ctx_s* self, tsk_bool_t use_rtcpmux);
+TINYNET_API int tnet_ice_ctx_set_ssl_certs(struct tnet_ice_ctx_s* self, const char* path_priv, const char* path_pub, const char* path_ca, tsk_bool_t verify);
+TINYNET_API tsk_size_t tnet_ice_ctx_count_local_candidates(const struct tnet_ice_ctx_s* self);
+TINYNET_API tsk_bool_t tnet_ice_ctx_got_local_candidates(const struct tnet_ice_ctx_s* self);
+TINYNET_API const struct tnet_ice_candidate_s* tnet_ice_ctx_get_local_candidate_at(const struct tnet_ice_ctx_s* self, tsk_size_t index);
+#define tnet_ice_ctx_get_local_candidate_first(self) tnet_ice_ctx_get_local_candidate_at((self), 0)
+TINYNET_API tsk_bool_t tnet_ice_ctx_is_started(const struct tnet_ice_ctx_s* self);
+TINYNET_API tsk_bool_t tnet_ice_ctx_is_active(const struct tnet_ice_ctx_s* self);
+TINYNET_API tsk_bool_t tnet_ice_ctx_is_turn_rtp_active(const struct tnet_ice_ctx_s* self);
+TINYNET_API tsk_bool_t tnet_ice_ctx_is_turn_rtcp_active(const struct tnet_ice_ctx_s* self);
+TINYNET_API tsk_bool_t tnet_ice_ctx_is_connected(const struct tnet_ice_ctx_s* self);
+TINYNET_API tsk_bool_t tnet_ice_ctx_is_can_send(const struct tnet_ice_ctx_s* self);
+TINYNET_API tsk_bool_t tnet_ice_ctx_is_can_recv(const struct tnet_ice_ctx_s* self);
+TINYNET_API tsk_bool_t tnet_ice_ctx_use_ipv6(const struct tnet_ice_ctx_s* self);
+TINYNET_API tsk_bool_t tnet_ice_ctx_use_rtcp(const struct tnet_ice_ctx_s* self);
+TINYNET_API int tnet_ice_ctx_get_nominated_symetric_candidates(const struct tnet_ice_ctx_s* self, uint32_t comp_id,
+ const struct tnet_ice_candidate_s** candidate_offer,
+ const struct tnet_ice_candidate_s** candidate_answer_src,
+ const struct tnet_ice_candidate_s** candidate_answer_dest);
+TINYNET_API int tnet_ice_ctx_recv_stun_message(struct tnet_ice_ctx_s* self, const void* data, tsk_size_t size, tnet_fd_t local_fd, const struct sockaddr_storage* remote_addr, tsk_bool_t *role_conflict);
+TINYNET_API int tnet_ice_ctx_send_turn_rtp(struct tnet_ice_ctx_s* self, const void* data, tsk_size_t size);
+TINYNET_API int tnet_ice_ctx_send_turn_rtcp(struct tnet_ice_ctx_s* self, const void* data, tsk_size_t size);
+
+TINYNET_API int tnet_ice_ctx_turn_get_bytes_count(const struct tnet_ice_ctx_s* self, uint64_t* bytes_in, uint64_t* bytes_out);
+TINYNET_API const char* tnet_ice_ctx_get_ufrag(const struct tnet_ice_ctx_s* self);
+TINYNET_API const char* tnet_ice_ctx_get_pwd(const struct tnet_ice_ctx_s* self);
+
+TINYNET_API int tnet_ice_ctx_set_proxy_auto_detect(struct tnet_ice_ctx_s* self, tsk_bool_t auto_detect);
+TINYNET_API int tnet_ice_ctx_set_proxy_info(struct tnet_ice_ctx_s* self, enum tnet_proxy_type_e type, const char* host, tnet_port_t port, const char* login, const char* password);
+
+TINYNET_API int tnet_ice_ctx_cancel(struct tnet_ice_ctx_s* self);
+TINYNET_API int tnet_ice_ctx_stop(struct tnet_ice_ctx_s* self);
+
+
+TNET_END_DECLS
+
+#endif /* TNET_ICE_CTX_H */
diff --git a/tinyNET/src/ice/tnet_ice_event.c b/tinyNET/src/ice/tnet_ice_event.c
new file mode 100644
index 0000000..480202f
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice_event.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012-2014 Mamadou DIOP
+ * Copyright (C) 2012-2014 Doubango Telecom <http://www.doubango.org>.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+#include "tnet_ice_event.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+static tsk_object_t* tnet_ice_event_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_ice_event_t *e = self;
+ if(e){
+
+ }
+ return self;
+}
+static tsk_object_t* tnet_ice_event_dtor(tsk_object_t * self)
+{
+ tnet_ice_event_t *e = self;
+ if(e){
+ TSK_SAFE_FREE(e->phrase);
+ TSK_OBJECT_SAFE_FREE(e->action);
+ e->ctx = tsk_null; // not the owner (const)
+ }
+
+ return self;
+}
+static const tsk_object_def_t tnet_ice_event_def_s =
+{
+ sizeof(tnet_ice_event_t),
+ tnet_ice_event_ctor,
+ tnet_ice_event_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_ice_event_def_t = &tnet_ice_event_def_s;
+
+
+tnet_ice_event_t* tnet_ice_event_create(const struct tnet_ice_ctx_s* ctx, tnet_ice_event_type_t type, const char* phrase, const void* userdata)
+{
+ tnet_ice_event_t* e;
+
+ if((e = tsk_object_new(tnet_ice_event_def_t))){
+ e->ctx = ctx;
+ e->type = type;
+ e->phrase = tsk_strdup(phrase);
+ e->userdata = userdata;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create ICE event");
+ }
+
+ return e;
+}
+
+int tnet_ice_event_set_action(tnet_ice_event_t* self, struct tnet_ice_action_s* action)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->type = tnet_ice_event_type_action;
+ TSK_OBJECT_SAFE_FREE(self->action);
+ if(action){
+ self->action = tsk_object_ref(action);
+ }
+ return 0;
+}
diff --git a/tinyNET/src/ice/tnet_ice_event.h b/tinyNET/src/ice/tnet_ice_event.h
new file mode 100644
index 0000000..8f2f72e
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice_event.h
@@ -0,0 +1,75 @@
+/*
+* Copyright (C) 2012-2014 Mamadou DIOP
+* Copyright (C) 2012-2014 Doubango Telecom <http://www.doubango.org>.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+#ifndef TNET_ICE_EVENT_H
+#define TNET_ICE_EVENT_H
+
+#include "tinynet_config.h"
+
+#include "tsk_object.h"
+
+TNET_BEGIN_DECLS
+
+typedef enum tnet_ice_event_type_e
+{
+ // Public events
+ tnet_ice_event_type_started,
+ tnet_ice_event_type_start_failed,
+ tnet_ice_event_type_stopped,
+ tnet_ice_event_type_stop_failed,
+ tnet_ice_event_type_gathering_host_candidates_failed,
+ tnet_ice_event_type_gathering_host_candidates_succeed,
+ tnet_ice_event_type_gathering_reflexive_candidates_failed,
+ tnet_ice_event_type_gathering_reflexive_candidates_succeed,
+ tnet_ice_event_type_gathering_relay_candidates_failed,
+ tnet_ice_event_type_gathering_relay_candidates_succeed,
+ tnet_ice_event_type_gathering_completed,
+ tnet_ice_event_type_conncheck_succeed,
+ tnet_ice_event_type_conncheck_failed,
+ tnet_ice_event_type_cancelled,
+ tnet_ice_event_type_turn_connection_broken,
+
+ // Private events
+ tnet_ice_event_type_action
+}
+tnet_ice_event_type_t;
+
+typedef struct tnet_ice_event_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_ice_event_type_t type;
+ char* phrase;
+ struct tnet_ice_action_s* action;
+ const struct tnet_ice_ctx_s* ctx;
+
+ const void* userdata;
+}
+tnet_ice_event_t;
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_ice_event_def_t;
+
+tnet_ice_event_t* tnet_ice_event_create(const struct tnet_ice_ctx_s* ctx, tnet_ice_event_type_t type, const char* phrase, const void* userdata);
+int tnet_ice_event_set_action(tnet_ice_event_t* self, struct tnet_ice_action_s* action);
+
+TNET_END_DECLS
+
+#endif /* TNET_ICE_EVENT_H */
diff --git a/tinyNET/src/ice/tnet_ice_pair.c b/tinyNET/src/ice/tnet_ice_pair.c
new file mode 100644
index 0000000..33e71a5
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice_pair.c
@@ -0,0 +1,988 @@
+/*
+ * Copyright (C) 2012-2015 Mamadou DIOP
+ * Copyright (C) 2012-2015 Doubango Telecom <http://www.doubango.org>.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+#include "tnet_ice_pair.h"
+#include "tnet_ice_utils.h"
+#include "tnet_ice_candidate.h"
+
+#include "stun/tnet_stun.h"
+#include "stun/tnet_stun_message.h"
+#include "stun/tnet_stun_types.h"
+#include "turn/tnet_turn_session.h"
+
+#include "tnet_endianness.h"
+#include "tnet_utils.h"
+
+#include "tsk_hmac.h"
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h> /* INT_MIN, INT_MAX */
+
+#if !defined(TNET_ICE_PAIR_FULL_DEBUG)
+# define TNET_ICE_PAIR_FULL_DEBUG 0
+#endif /* TNET_ICE_PAIR_FULL_DEBUG */
+
+#if TNET_ICE_PAIR_FULL_DEBUG
+#define TNET_ICE_PAIR_DEBUG_INFO TSK_DEBUG_INFO
+#else
+#define TNET_ICE_PAIR_DEBUG_INFO(...) ((void)0)
+#endif
+
+// 8.1.1.1. Regular Nomination : https://tools.ietf.org/html/rfc5245#section-8.1.1.1
+// 8.1.1.2. Aggressive Nomination : https://tools.ietf.org/html/rfc5245#section-8.1.1.2
+// Issues with chrome on some restrictive networks (GE-issue)
+#if !defined(TNET_ICE_AGGRESSIVE_NOMINATION)
+# define TNET_ICE_AGGRESSIVE_NOMINATION 0
+#endif /* TNET_ICE_AGGRESSIVE_NOMINATION */
+
+static int __pred_find_by_pair(const tsk_list_item_t *item, const void *pair)
+{
+ if(item && item->data){
+ int ret;
+ tsk_subsat_int32_ptr(item->data, pair, &ret);
+ return ret;
+ }
+ return -1;
+}
+
+
+static tsk_object_t* tnet_ice_pair_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_ice_pair_t *pair = self;
+ if(pair){
+ pair->state_offer = tnet_ice_pair_state_frozen;
+ pair->state_answer = tnet_ice_pair_state_frozen;
+ }
+ return self;
+}
+static tsk_object_t* tnet_ice_pair_dtor(tsk_object_t * self)
+{
+ tnet_ice_pair_t *pair = self;
+ if (pair) {
+ TSK_OBJECT_SAFE_FREE(pair->candidate_offer);
+ TSK_OBJECT_SAFE_FREE(pair->candidate_answer);
+ TSK_OBJECT_SAFE_FREE(pair->last_request);
+ }
+ return self;
+}
+static int tnet_ice_pair_cmp(const tsk_object_t *_p1, const tsk_object_t *_p2)
+{
+ const tnet_ice_pair_t *p1 = _p1;
+ const tnet_ice_pair_t *p2 = _p2;
+
+ if (p1 && p2) {
+#if 0
+ // This is not correct and most differences (if not all) will be equal to "INT_MIN" or "INT_MAX" and this will produce invalid sorting.
+ static const int64_t __int_min = INT_MIN;
+ static const int64_t __int_max = INT_MAX;
+ return (int)(TSK_CLAMP(__int_min, (int64_t)(p1->priority - p2->priority), __int_max));
+#else
+ // The comparison is used for sorting only which means the below code is correct
+ return (p1->priority == p2->priority) ? 0 : (p1->priority > p2->priority ? 1 : -1);
+#endif
+ }
+ else if (!p1 && !p2) return 0;
+ else return -1;
+}
+static const tsk_object_def_t tnet_ice_pair_def_s =
+{
+ sizeof(tnet_ice_pair_t),
+ tnet_ice_pair_ctor,
+ tnet_ice_pair_dtor,
+ tnet_ice_pair_cmp,
+};
+
+tnet_ice_pair_t* tnet_ice_pair_create(const tnet_ice_candidate_t* candidate_offer, const tnet_ice_candidate_t* candidate_answer, tsk_bool_t is_controlling, uint64_t tie_breaker, tsk_bool_t is_ice_jingle)
+{
+ static uint64_t __unique_id = 0;
+ tnet_ice_pair_t *pair;
+ if(!candidate_offer || !candidate_answer){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ if ((pair = tsk_object_new(&tnet_ice_pair_def_s))) {
+ uint64_t G, D;
+ pair->id = ++__unique_id; // not part of the standard, used to ease debugging
+ pair->candidate_offer = tsk_object_ref((tsk_object_t*)candidate_offer);
+ pair->candidate_answer = tsk_object_ref((tsk_object_t*)candidate_answer);
+ pair->is_controlling = is_controlling;
+ pair->tie_breaker = tie_breaker;
+ pair->is_ice_jingle = is_ice_jingle;
+ // 5.7.2. Computing Pair Priority and Ordering Pairs: https://tools.ietf.org/html/rfc5245#section-5.7.2
+ G = is_controlling ? candidate_offer->priority : candidate_answer->priority; // the priority for the candidate provided by the controlling agent
+ D = is_controlling ? candidate_answer->priority : candidate_offer->priority; // the priority for the candidate provided by the controlled agent
+ pair->priority = ((TSK_MIN(G, D)) << 32) + (TSK_MAX(G, D) << 1) + ((G > D) ? 1 : 0);
+ pair->turn_peer_id = kTurnPeerIdInvalid;
+ }
+
+ return pair;
+}
+
+// rfc 5245 - 7.1.3.2.1. Discovering Peer Reflexive Candidates
+tnet_ice_pair_t* tnet_ice_pair_prflx_create(tnet_ice_pairs_L_t* pairs, tnet_fd_t local_fd, const struct sockaddr_storage *remote_addr)
+{
+ int ret;
+ const tsk_list_item_t *item;
+ const tnet_ice_pair_t *pair_local = tsk_null, *pair = tsk_null;
+ tnet_ip_t remote_ip;
+ tnet_port_t remote_port;
+
+ if (!pairs || !remote_addr) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ tsk_list_foreach(item, pairs) {
+ if (!(pair = item->data) || !pair->candidate_offer || !pair->candidate_answer || !pair->candidate_offer->socket || pair->candidate_offer->socket->fd != local_fd) {
+ continue;
+ }
+ pair_local = pair;
+ break;
+ }
+
+ if ((ret = tnet_get_sockip_n_port((const struct sockaddr*)remote_addr, &remote_ip, &remote_port))) {
+ TNET_PRINT_LAST_ERROR("tnet_get_sockip_n_port() failed");
+ return tsk_null;
+ }
+
+ if (!pair_local) {
+ TSK_DEBUG_ERROR("Cannot create prflx candidate with remote ip = %s, remote port = %u and local_fd = %d", remote_ip, remote_port, local_fd);
+ return tsk_null;
+ }
+ else {
+ tnet_ice_pair_t* pair_peer = tsk_null;
+ tnet_ice_candidate_t* cand_local;
+ tnet_ice_candidate_t* cand_remote;
+ cand_local = tnet_ice_candidate_create(tnet_ice_cand_type_prflx, pair_local->candidate_offer->socket, pair_local->is_ice_jingle, pair_local->candidate_offer->is_rtp, pair_local->candidate_offer->is_video, pair_local->candidate_offer->ufrag, pair_local->candidate_offer->pwd, pair_local->candidate_offer->foundation);
+ cand_remote = tnet_ice_candidate_create(tnet_ice_cand_type_prflx, tsk_null, pair_local->is_ice_jingle, pair_local->candidate_answer->is_rtp, pair_local->candidate_answer->is_video, pair_local->candidate_answer->ufrag, pair_local->candidate_answer->pwd, pair_local->candidate_answer->foundation);
+ if (cand_local && cand_remote) {
+ tsk_strupdate(&cand_remote->transport_str, pair_local->candidate_offer->transport_str);
+ cand_remote->comp_id = pair_local->candidate_offer->comp_id;
+ memcpy(cand_remote->connection_addr, remote_ip, sizeof(tnet_ip_t));
+ cand_remote->port = remote_port;
+
+ TSK_DEBUG_INFO("ICE Pair Reflexive Candidate (%llu, %llu): [%s %u %u %s %d] -> [%s %u %u %s %d]",
+ pair->id,
+ pair->priority,
+
+ cand_local->foundation,
+ cand_local->priority,
+ cand_local->comp_id,
+ cand_local->connection_addr,
+ cand_local->port,
+
+ cand_remote->foundation,
+ cand_remote->priority,
+ cand_remote->comp_id,
+ cand_remote->connection_addr,
+ cand_remote->port);
+
+ pair_peer = tnet_ice_pair_create(cand_local, cand_remote, pair_local->is_controlling, pair_local->tie_breaker, pair_local->is_ice_jingle);
+ }
+ TSK_OBJECT_SAFE_FREE(cand_local);
+ TSK_OBJECT_SAFE_FREE(cand_remote);
+ return pair_peer;
+ }
+
+ return tsk_null;
+}
+
+int tnet_ice_pair_send_conncheck(tnet_ice_pair_t *self)
+{
+ int ret;
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (self->candidate_offer->turn.ss) {
+ enum tnet_stun_state_e e_state;
+ enum tnet_turn_transport_e e_req_transport;
+ if ((ret = tnet_turn_session_get_state_createperm(self->candidate_offer->turn.ss, self->turn_peer_id, &e_state))) {
+ goto bail;
+ }
+ if (e_state != tnet_stun_state_ok) {
+ TSK_DEBUG_INFO("TURN CreatePerm not ready yet... to send STUN ConnCheck (peer-id=%ld)", self->turn_peer_id);
+ goto bail;
+ }
+
+ if ((ret = tnet_turn_session_get_req_transport(self->candidate_offer->turn.ss, &e_req_transport))) {
+ goto bail;
+ }
+ if (e_req_transport == tnet_turn_transport_tcp) {
+ // Make sure "ConnectionBind" sent and underlaying socket is connected
+ tsk_bool_t b_connected;
+ if ((ret = tnet_turn_session_is_stream_connected(self->candidate_offer->turn.ss, self->turn_peer_id, &b_connected))) {
+ goto bail;
+ }
+ if (!b_connected) {
+ TSK_DEBUG_INFO("TURN/TCP not connected yet... to send STUN ConnCheck");
+ goto bail;
+ }
+ }
+ }
+
+ if (!self->last_request) {
+ uint32_t priority;
+
+ // Init remote address
+ if ((ret = tnet_sockaddr_init(self->candidate_answer->connection_addr, self->candidate_answer->port, self->candidate_offer->socket->type, &self->remote_addr))) {
+ TNET_PRINT_LAST_ERROR("tnet_sockaddr_init(%s:%d) failed", self->candidate_answer->connection_addr, self->candidate_answer->port);
+ goto bail;
+ }
+
+ if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_binding_request, &self->last_request))) {
+ goto bail;
+ }
+ // 7.1.2.3. Forming Credentials
+ // username= "RFRAG:LFRAG"
+ // password= "RPASS"
+ {
+ char* p_uname = tsk_null;
+ const char* pc_pwd;
+ if (self->is_ice_jingle) {
+ tsk_sprintf(&p_uname, "%s%s", tnet_ice_candidate_get_ufrag(self->candidate_answer), tnet_ice_candidate_get_ufrag(self->candidate_offer));
+ }
+ else{
+ tsk_sprintf(&p_uname, "%s:%s", tnet_ice_candidate_get_ufrag(self->candidate_answer), tnet_ice_candidate_get_ufrag(self->candidate_offer));
+ }
+ pc_pwd = tnet_ice_candidate_get_pwd(self->candidate_answer);
+ ret = tnet_stun_pkt_auth_prepare_shortterm(self->last_request, p_uname, pc_pwd);
+ TSK_FREE(p_uname);
+ if (ret) {
+ goto bail;
+ }
+ }
+
+ priority = tnet_ice_utils_get_priority(tnet_ice_cand_type_prflx, self->candidate_offer->local_pref, self->candidate_offer->is_rtp);
+ // add attributes
+ self->last_request->opt.dontfrag = 0;
+ ret = tnet_stun_pkt_attrs_add(self->last_request,
+ TNET_STUN_PKT_ATTR_ADD_SOFTWARE_ZT(kStunSoftware),
+ // 7.1.2.1. PRIORITY
+ TNET_STUN_PKT_ATTR_ADD_ICE_PRIORITY(priority),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ // 7.1.2.2. ICE-CONTROLLING / ICE-CONTROLLED
+ if (self->is_controlling) {
+ ret = tnet_stun_pkt_attrs_add(self->last_request,
+ // 7.1.2.2. ICE-CONTROLLING
+ TNET_STUN_PKT_ATTR_ADD_ICE_CONTROLLING(self->tie_breaker),
+ // 7.1.2.1. USE-CANDIDATE - aggressive mode
+#if TNET_ICE_AGGRESSIVE_NOMINATION
+ TNET_STUN_PKT_ATTR_ADD_ICE_USE_CANDIDATE(),
+#endif
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (self->is_nominated) {
+ ret = tnet_stun_pkt_attrs_add(self->last_request,
+ TNET_STUN_PKT_ATTR_ADD_ICE_USE_CANDIDATE(),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ }
+ if (ret) {
+ goto bail;
+ }
+ }
+ else {
+ ret = tnet_stun_pkt_attrs_add(self->last_request,
+ // 7.1.2.2. ICE-CONTROLLED
+ TNET_STUN_PKT_ATTR_ADD_ICE_CONTROLLED(self->tie_breaker),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ }
+ }
+ else {
+ tsk_bool_t b_changed = tsk_false;
+ if (self->is_controlling) {
+ tnet_stun_pkt_attr_remove(self->last_request, tnet_stun_attr_type_ice_controlled);
+ if (!tnet_stun_pkt_attr_exists(self->last_request, tnet_stun_attr_type_ice_controlling)) {
+ ret = tnet_stun_pkt_attrs_add(self->last_request,
+ TNET_STUN_PKT_ATTR_ADD_ICE_CONTROLLING(self->tie_breaker),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ b_changed = tsk_true;
+ }
+#if TNET_ICE_AGGRESSIVE_NOMINATION
+ if (!tnet_stun_pkt_attr_exists(self->last_request, tnet_stun_attr_type_ice_use_candidate)) {
+#else
+ if (self->is_nominated && !tnet_stun_pkt_attr_exists(self->last_request, tnet_stun_attr_type_ice_use_candidate)) {
+#endif
+ ret = tnet_stun_pkt_attrs_add(self->last_request,
+ TNET_STUN_PKT_ATTR_ADD_ICE_USE_CANDIDATE(),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+
+ if (ret) {
+ goto bail;
+ }
+ b_changed = tsk_true;
+ }
+ }
+ else {
+ tnet_stun_pkt_attr_remove(self->last_request, tnet_stun_attr_type_ice_use_candidate);
+ tnet_stun_pkt_attr_remove(self->last_request, tnet_stun_attr_type_ice_controlling);
+ if (!tnet_stun_pkt_attr_exists(self->last_request, tnet_stun_attr_type_ice_controlled)) {
+ ret = tnet_stun_pkt_attrs_add(self->last_request,
+ TNET_STUN_PKT_ATTR_ADD_ICE_CONTROLLED(self->tie_breaker),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ b_changed = tsk_true;
+ }
+ }
+ // update transac-id if the request structure changed
+ if ((b_changed && (ret = tnet_stun_utils_transac_id_rand(&self->last_request->transac_id)))) {
+ goto bail;
+ }
+ }
+
+ // Send request
+ {
+ tsk_buffer_t *req_buffer = tsk_null;
+ self->last_request->opt.fingerprint = !self->is_ice_jingle;
+ if ((ret = tnet_stun_pkt_write_with_padding_2(self->last_request, &req_buffer))) {
+ goto bail;
+ }
+ if (self->candidate_offer->turn.ss) {
+ // Send using TURN session. Above, we already checked that the TURN session is ready (Alloc=OK, Permission=OK)
+ ret = tnet_turn_session_send_data(self->candidate_offer->turn.ss, self->turn_peer_id, req_buffer->data, (uint16_t)req_buffer->size);
+ }
+ else {
+ int sendBytes = tnet_sockfd_sendto(self->candidate_offer->socket->fd, (const struct sockaddr*)&self->remote_addr, req_buffer->data, req_buffer->size);
+ ret = (sendBytes == req_buffer->size) ? 0 : -9;
+ }
+ TSK_OBJECT_SAFE_FREE(req_buffer);
+ if (ret) {
+ goto bail;
+ }
+ }
+
+ bail:
+ if (ret == 0 && self->state_offer == tnet_ice_pair_state_frozen) {
+ self->state_offer = tnet_ice_pair_state_in_progress;
+ }
+ return ret;
+ }
+
+ int tnet_ice_pair_send_response(tnet_ice_pair_t *self, const tnet_stun_pkt_req_t* request, const short code, const char* phrase, const struct sockaddr_storage *remote_addr)
+ {
+ tnet_stun_pkt_t* message = tsk_null;
+ const char *password, *username;
+ int ret = -1;
+ tsk_bool_t is_error = ((code / 100) != 2);
+
+ if(!self || !phrase || !request || !self->candidate_offer || !self->candidate_answer){
+ TSK_DEBUG_ERROR("Invalid paramter");
+ return -1;
+ }
+
+ username = tsk_null;
+ password = tnet_ice_candidate_get_pwd(self->candidate_offer);
+
+ if ((ret = tnet_stun_pkt_create_empty(is_error ? tnet_stun_pkt_type_binding_error_response : tnet_stun_pkt_type_binding_success_response, &message)) == 0) {
+ tsk_buffer_t *req_buffer = tsk_null;
+ memcpy(message->transac_id, request->transac_id, sizeof(request->transac_id));
+ message->opt.fingerprint = !self->is_ice_jingle;
+ message->opt.dontfrag = 0;
+
+ // SOFWARE
+ ret = tnet_stun_pkt_attrs_add(message,
+ TNET_STUN_PKT_ATTR_ADD_SOFTWARE_ZT(kStunSoftware),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+
+ // SHORT-TERM authentication even for responses
+ if ((ret = tnet_stun_pkt_auth_prepare_shortterm_2(message, password))) {
+ goto bail;
+ }
+
+ // ERROR
+ if (is_error) {
+ ret = tnet_stun_pkt_attrs_add(message,
+ TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(((code / 100) & 0x07), (code - ((code / 100) * 100)), phrase),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ }
+ else {
+ tnet_ip_t remote_ip;
+ tnet_port_t remote_port;
+ if (self->is_ice_jingle) {
+ const tnet_stun_attr_vdata_t *pc_attr_vdata;
+ // USERNAME
+ if ((ret = tnet_stun_pkt_attr_find_first(request, tnet_stun_attr_type_username, (const tnet_stun_attr_t **)&pc_attr_vdata)) == 0 && pc_attr_vdata) {
+ ret = tnet_stun_pkt_attrs_add(message,
+ TNET_STUN_PKT_ATTR_ADD_USERNAME(pc_attr_vdata->p_data_ptr, pc_attr_vdata->u_data_size),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ }
+ }
+ // MAPPED-ADDRESS and XOR-MAPPED-ADDRESS
+ if ((ret = tnet_get_sockip_n_port((const struct sockaddr*)remote_addr, &remote_ip, &remote_port)) == 0) {
+ tnet_stun_addr_t _addr;
+ tnet_stun_address_family_t _familly = (remote_addr->ss_family == AF_INET6) ? tnet_stun_address_family_ipv6 : tnet_stun_address_family_ipv4;
+ if ((ret = tnet_stun_utils_inet_pton((_familly == tnet_stun_address_family_ipv6), remote_ip, &_addr)) == 0) {
+ ret = tnet_stun_pkt_attrs_add(message,
+ TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS(_familly, remote_port, &_addr),
+ TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS(_familly, remote_port, &_addr),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ }
+ }
+ }
+
+ if (self->candidate_offer->turn.ss) {
+ enum tnet_stun_state_e e_state;
+ if ((ret = tnet_turn_session_get_state_createperm(self->candidate_offer->turn.ss, self->turn_peer_id, &e_state))) {
+ goto bail;
+ }
+ if (e_state != tnet_stun_state_ok) {
+ TSK_DEBUG_INFO("TURN CreatePerm not ready yet... to send STUN response (peer-id=%ld)", self->turn_peer_id);
+ goto bail;
+ }
+ if ((ret = tnet_stun_pkt_write_with_padding_2(message, &req_buffer))) {
+ goto bail;
+ }
+ if ((ret = tnet_turn_session_send_data(self->candidate_offer->turn.ss, self->turn_peer_id, req_buffer->data, (uint16_t)req_buffer->size))) {
+ goto bail;
+ }
+ }
+ else {
+ struct sockaddr_storage dest_addr;
+ int sendBytes;
+ if ((ret = tnet_sockaddr_init(self->candidate_answer->connection_addr, self->candidate_answer->port, self->candidate_offer->socket->type, &dest_addr))) {
+ TNET_PRINT_LAST_ERROR("tnet_sockaddr_init(%s:%d) failed", self->candidate_answer->connection_addr, self->candidate_answer->port);
+ goto bail;
+ }
+ if ((ret = tnet_stun_pkt_write_with_padding_2(message, &req_buffer))) {
+ goto bail;
+ }
+ sendBytes = tnet_sockfd_sendto(self->candidate_offer->socket->fd, (const struct sockaddr*)&dest_addr, req_buffer->data, req_buffer->size);
+ TSK_OBJECT_SAFE_FREE(req_buffer);
+ ret = (sendBytes > 0) ? 0 : -2;
+ if (ret != 0) {
+ TSK_DEBUG_ERROR("ICE pair-answer: failed to send response");
+ }
+ }
+ }
+
+ if (ret == 0 && !is_error) {
+ tsk_bool_t change_state =
+ self->is_ice_jingle // ICE-JINGLE don't have ICE-CONTROLLING/ICE-CONTROLLED attributes
+ || (!self->is_controlling && tnet_stun_pkt_attr_exists(request, tnet_stun_attr_type_ice_use_candidate)) // Sender is controlling and uses "ICE-USE-CANDIDATE" attribute
+#if TNET_ICE_AGGRESSIVE_NOMINATION || 1 // This is not a typo but a *must*. We've to change the answer state regardless the nomination mode otherwise we'll never get a nominee. Only the offer state is controlled based on the mode and depends on "is_nominated".
+ || (self->is_controlling) // We are controlling and using aggressive mode
+#else
+ || (self->is_controlling && self->is_nominated) // We're controlling and using regular mode
+#endif
+ ;
+ TNET_ICE_PAIR_DEBUG_INFO("ICE pair-answer changing state to 'succeed' ? %s, comp-id=%d, found=%s, addr=%s",
+ change_state?"yes":"no",
+ self->candidate_answer->comp_id,
+ self->candidate_answer->foundation,
+ self->candidate_answer->connection_addr
+ );
+ if (change_state) {
+ self->state_answer = tnet_ice_pair_state_succeed;
+ }
+ }
+
+
+ bail:
+ TSK_OBJECT_SAFE_FREE(message);
+ return ret;
+ }
+
+ int tnet_ice_pair_auth_conncheck(const tnet_ice_pair_t *self, const tnet_stun_pkt_req_t* request, const void* request_buff, tsk_size_t request_buff_size, short* resp_code, char** resp_phrase)
+ {
+ const uint8_t* _request_buff = (const uint8_t*)request_buff;
+
+ const tnet_stun_attr_t* stun_att;
+ const tnet_stun_attr_vdata_t *stun_att_usr_name;
+ const tnet_stun_attr_vdata_t *stun_att_fingerprint;
+ const tnet_stun_attr_vdata_t *stun_att_integrity;
+
+ const tsk_list_item_t *item;
+ tsk_sha1digest_t hmac;
+ const char* pwd;
+
+ tsk_size_t msg_integrity_start = 0, length, i;
+
+ if(!self || !request || !request_buff || !request_buff_size || !resp_code || !resp_phrase){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!TNET_STUN_BUFF_IS_STUN2(_request_buff, request_buff_size)){
+ TSK_DEBUG_ERROR("Not STUN buffer");
+ return -1;
+ }
+
+ pwd = tnet_ice_candidate_get_pwd(self->candidate_offer);
+ stun_att_usr_name = tsk_null;
+ stun_att_fingerprint = tsk_null;
+ stun_att_integrity = tsk_null;
+
+ tsk_list_foreach(item, request->p_list_attrs) {
+ if ((!(stun_att = (const tnet_stun_attr_t*)item->data))) {
+ continue;
+ }
+
+ switch (stun_att->hdr.e_type) {
+ case tnet_stun_attr_type_username:
+ {
+ stun_att_usr_name = (const tnet_stun_attr_vdata_t *)stun_att;
+ break;
+ }
+ case tnet_stun_attr_type_fingerprint:
+ {
+ stun_att_fingerprint = (const tnet_stun_attr_vdata_t *)stun_att;
+ break;
+ }
+ case tnet_stun_attr_type_message_integrity:
+ {
+ stun_att_integrity = (const tnet_stun_attr_vdata_t *)stun_att;
+ break;
+ }
+ default: break;
+ }
+
+ if (!stun_att_integrity) {
+ if ((length = (kStunAttrHdrSizeInOctets + stun_att->hdr.u_length)) & 0x03) {
+ length += (4 - (length & 0x03));
+ }
+ msg_integrity_start += length;
+ }
+ }
+
+ if (!stun_att_usr_name) {
+ TSK_DEBUG_ERROR("USERNAME is missing");
+ *resp_code = 400;
+ tsk_strupdate(resp_phrase, "USERNAME is missing");
+ return -2;
+ }
+
+ if (!stun_att_integrity || stun_att_integrity->u_data_size != TSK_SHA1_DIGEST_SIZE) {
+ if (self->is_ice_jingle) { // Bug introduced in Chrome 20.0.1120.0 (Not security issue as ICE-JINGLE is deprecated and will never be ON)
+ *resp_code = 200;
+ tsk_strupdate(resp_phrase, "MESSAGE-INTEGRITY is missing but accepted");
+ return 0;
+ }
+ else {
+ TSK_DEBUG_ERROR("MESSAGE-INTEGRITY is missing");
+ *resp_code = 400;
+ tsk_strupdate(resp_phrase, "MESSAGE-INTEGRITY is missing");
+ return -3;
+ }
+ }
+
+ if ((kStunPktHdrSizeInOctets + msg_integrity_start) >= request_buff_size) {
+ TSK_DEBUG_ERROR("Invalid length");
+ *resp_code = 400;
+ tsk_strupdate(resp_phrase, "Invalid length");
+ return -20;
+ }
+
+ if (request->u_length != msg_integrity_start) {
+ tsk_size_t size = (kStunPktHdrSizeInOctets + msg_integrity_start);
+ uint8_t* new_buffer = (uint8_t*)tsk_calloc(size, 1);
+ if (!new_buffer) {
+ TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", (unsigned)msg_integrity_start);
+ return -30;
+ }
+ memcpy(new_buffer, request_buff, size);
+ length = msg_integrity_start + (kStunAttrHdrSizeInOctets + TSK_SHA1_DIGEST_SIZE /* INTEGRITY VALUE*/);
+ new_buffer[2] = (length >> 8) & 0xFF;
+ new_buffer[3] = (length & 0xFF);
+ hmac_sha1digest_compute(new_buffer, size, pwd, tsk_strlen(pwd), hmac);
+ TSK_FREE(new_buffer);
+ }
+ else {
+ // must never happen
+ hmac_sha1digest_compute(request_buff, request_buff_size, pwd, tsk_strlen(pwd), hmac);
+ }
+
+ for (i = 0; i < TSK_SHA1_DIGEST_SIZE; ++i) {
+ if (hmac[i] != stun_att_integrity->p_data_ptr[i]) {
+ TSK_DEBUG_ERROR("MESSAGE-INTEGRITY mismatch");
+ *resp_code = 401;
+ tsk_strupdate(resp_phrase, "MESSAGE-INTEGRITY mismatch");
+ return -40;
+ }
+ }
+
+ *resp_code = 200;
+ tsk_strupdate(resp_phrase, "Ok");
+
+ return 0;
+ }
+
+ int tnet_ice_pair_recv_response(tnet_ice_pair_t *self, const tnet_stun_pkt_resp_t* response, tsk_bool_t is_4conncheck)
+ {
+ if (self && response && TNET_STUN_PKT_IS_RESP(response)) {
+ if (self->last_request && tnet_stun_utils_transac_id_equals(self->last_request->transac_id, response->transac_id)){
+ // ignore errors (e.g. STALE-CREDENTIALS) which could happen in some special cases before success
+ if (TNET_STUN_PKT_RESP_IS_SUCCESS(response)) {
+ if (is_4conncheck) {
+ self->state_offer = tnet_ice_pair_state_succeed; // we must not change the state after connection cheking to make sure another pair won't be picked as nominated
+ TNET_ICE_PAIR_DEBUG_INFO("ICE pair-offer changing state to 'succeed', comp-id=%d, found=%s, addr=%s",
+ self->candidate_offer->comp_id,
+ self->candidate_offer->foundation,
+ self->candidate_offer->connection_addr
+ );
+ }
+ }
+ else {
+ // The response is an error
+ uint16_t u_code;
+ int ret;
+ if ((ret = tnet_stun_pkt_get_errorcode(response, &u_code)) == 0 && u_code == kStunErrCodeIceConflict) {
+ TSK_DEBUG_INFO("ICE Pair %llu received conflict error message", self->id);
+ // If this code is called this means that we have lower tie-breaker and we must toggle our role
+ self->is_controlling = !self->is_controlling;
+ TSK_OBJECT_SAFE_FREE(self->last_request); // delete the "last_request" to make sure a new one will be created with right attributes
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+ const tnet_ice_pair_t* tnet_ice_pairs_find_by_response(tnet_ice_pairs_L_t* pairs, const tnet_stun_pkt_t* response)
+ {
+ if(pairs && response){
+ const tsk_list_item_t *item;
+ const tnet_ice_pair_t *pair;
+ tnet_port_t mapped_port;
+ tnet_ip_t mapped_ip;
+ tsk_list_foreach(item, pairs){
+ if(!(pair = item->data) || !pair->candidate_answer || !pair->candidate_offer){
+ continue;
+ }
+ if(pair->last_request && tnet_stun_utils_transac_id_equals(pair->last_request->transac_id, response->transac_id)){
+ // check that mapped/xmapped address match destination
+ const tnet_stun_attr_address_t *xmapped_addr = tsk_null;
+ const tnet_stun_attr_address_t* mapped_addr = tsk_null;
+ const tnet_stun_attr_address_t* _addr;
+
+ tnet_stun_pkt_attr_find_first(response, tnet_stun_attr_type_xor_mapped_address, (const tnet_stun_attr_t **)&xmapped_addr);
+ tnet_stun_pkt_attr_find_first(response, tnet_stun_attr_type_mapped_address, (const tnet_stun_attr_t **)&mapped_addr);
+ _addr = xmapped_addr ? xmapped_addr : mapped_addr;
+
+ if (!_addr) {
+ return pair; // do nothing if the client doesn't return mapped address STUN attribute
+ }
+ /* rfc 5245 7.1.3.2.1. Discovering Peer Reflexive Candidates
+
+ The agent checks the mapped address from the STUN response. If the
+ transport address does not match any of the local candidates that the
+ agent knows about, the mapped address represents a new candidate -- a
+ peer reflexive candidate. Like other candidates, it has a type,
+ base, priority, and foundation. They are computed as follows:
+
+ o Its type is equal to peer reflexive.
+
+ o Its base is set equal to the local candidate of the candidate pair
+ from which the STUN check was sent.
+
+ o Its priority is set equal to the value of the PRIORITY attribute
+ in the Binding request.
+
+ o Its foundation is selected as described in Section 4.1.1.3.
+
+ This peer reflexive candidate is then added to the list of local
+ candidates for the media stream. Its username fragment and password
+ are the same as all other local candidates for that media stream.
+ */
+
+ tnet_stun_utils_inet_ntop((_addr->e_family == tnet_stun_address_family_ipv6), &_addr->address, &mapped_ip);
+ mapped_port = _addr->u_port;
+ if (pair->candidate_offer->type_e != tnet_ice_cand_type_host && (mapped_port != pair->candidate_offer->port || !tsk_striequals(mapped_ip, pair->candidate_offer->connection_addr))) {
+ TSK_DEBUG_INFO("Mapped address different than local connection address...probably symetric NAT: %s#%s or %u#%u",
+ pair->candidate_offer->connection_addr, mapped_ip,
+ pair->candidate_offer->port, mapped_port);
+ // do we really need to add new local candidate?
+ // continue;
+ }
+ return pair;
+ }
+ }
+ }
+ return tsk_null;
+ }
+
+ const tnet_ice_pair_t* tnet_ice_pairs_find_by_fd_and_addr(tnet_ice_pairs_L_t* pairs, tnet_fd_t local_fd, const struct sockaddr_storage *remote_addr)
+ {
+ int ret;
+ const tsk_list_item_t *item;
+ const tnet_ice_pair_t *pair;
+ tnet_ip_t remote_ip;
+ tnet_port_t remote_port;
+
+ if(!pairs || !remote_addr){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ if((ret = tnet_get_sockip_n_port((const struct sockaddr*)remote_addr, &remote_ip, &remote_port))){
+ TNET_PRINT_LAST_ERROR("tnet_get_sockip_n_port() failed");
+ return tsk_null;
+ }
+
+ tsk_list_foreach(item, pairs){
+ if (!(pair = item->data) || !pair->candidate_offer || !pair->candidate_offer->socket || pair->candidate_offer->socket->fd != local_fd) {
+ continue;
+ }
+ if (!tsk_striequals(pair->candidate_answer->connection_addr, remote_ip) || pair->candidate_answer->port != remote_port) {
+ continue;
+ }
+
+ return pair;
+ }
+
+ TSK_DEBUG_INFO("No ICE candidate with remote ip = %s, port = %u and local_fd = %d could be found...probably symetric NAT", remote_ip, remote_port, local_fd);
+
+ return tsk_null;
+ }
+
+
+ static tsk_bool_t _tnet_ice_pairs_none_succeed(const tnet_ice_pairs_L_t* pairs, uint32_t comp_id, const char* foundation, tsk_bool_t answer){
+ if(pairs && foundation){
+ const tsk_list_item_t *item;
+ const tnet_ice_pair_t *pair;
+ const tnet_ice_candidate_t* candidate;
+ tsk_list_foreach(item, pairs){
+ if(!(pair = item->data) || !(candidate = (answer ? pair->candidate_answer : pair->candidate_offer))){
+ continue;
+ }
+ if(candidate->comp_id != comp_id || !tsk_striequals(candidate->foundation, foundation)){
+ continue;
+ }
+ if((answer ? pair->state_answer : pair->state_offer) == tnet_ice_pair_state_succeed){
+ TNET_ICE_PAIR_DEBUG_INFO("_tnet_ice_pairs_none_succeed_%s(%u, %s):false", answer?"anwser":"offer", comp_id, foundation);
+ return tsk_false;
+ }
+ }
+ }
+ TNET_ICE_PAIR_DEBUG_INFO("_tnet_ice_pairs_none_succeed_%s(%u, %s):true", answer?"anwser":"offer", comp_id, foundation);
+ return tsk_true;
+ }
+#define _tnet_ice_pairs_none_succeed_answer(pairs, comp_id, foundation) _tnet_ice_pairs_none_succeed((pairs), (comp_id), (foundation), tsk_true)
+#define _tnet_ice_pairs_none_succeed_offer(pairs, comp_id, foundation) _tnet_ice_pairs_none_succeed((pairs), (comp_id), (foundation), tsk_false)
+
+ // both RTP and RTCP have succeeded
+#define _tnet_ice_pairs_get_nominated_offer_at(pairs, index, comp_id, check_fullness, ret) _tnet_ice_pairs_get_nominated_at((pairs), offer, answer, (index), (comp_id), (check_fullness), (ret))
+#define _tnet_ice_pairs_get_nominated_answer_at(pairs, index, comp_id, check_fullness, ret) _tnet_ice_pairs_get_nominated_at((pairs), answer, offer, (index), (comp_id), (check_fullness), (ret))
+#define _tnet_ice_pairs_get_nominated_at(pairs, dir_1, dir_2, index, _comp_id, check_fullness, ret) \
+{ \
+ret = tsk_null; \
+if (pairs) { \
+const tsk_list_item_t *item; \
+const tnet_ice_pair_t *pair; \
+tsk_size_t pos = 0; \
+tsk_bool_t nominated; \
+tsk_list_foreach(item, pairs) { \
+if (!(pair = item->data)) { \
+continue; \
+} \
+TNET_ICE_PAIR_DEBUG_INFO("ICE pair(%d,dir_1) state=%d, compid=%d, found=%s, addr=%s", _comp_id, pair->state_##dir_1, pair->candidate_##dir_1->comp_id, pair->candidate_##dir_1->foundation, pair->candidate_##dir_1->connection_addr); \
+TNET_ICE_PAIR_DEBUG_INFO("ICE pair(%d,dir_2) state=%d, compid=%d, found=%s, addr=%s", _comp_id, pair->state_##dir_2, pair->candidate_##dir_2->comp_id, pair->candidate_##dir_2->foundation, pair->candidate_##dir_2->connection_addr); \
+if (pair->state_##dir_1 == tnet_ice_pair_state_succeed && pair->candidate_##dir_1->comp_id == _comp_id) { \
+nominated = tsk_true; \
+if (check_fullness) { \
+/* find another pair with same foundation but different comp-id (e.g. RTCP) */ \
+const tsk_list_item_t *item2; \
+const tnet_ice_pair_t *pair2; \
+tsk_list_foreach(item2, pairs) { \
+if (!(pair2 = item2->data)) { \
+continue; \
+} \
+TNET_ICE_PAIR_DEBUG_INFO("ICE pair2(dir_1) state=%d, compid=%d, found=%s, addr=%s", pair2->state_##dir_1, pair2->candidate_##dir_1->comp_id, pair2->candidate_##dir_1->foundation, pair2->candidate_##dir_1->connection_addr); \
+TNET_ICE_PAIR_DEBUG_INFO("ICE pair2(dir_2) state=%d, compid=%d, found=%s, addr=%s", pair2->state_##dir_2, pair2->candidate_##dir_2->comp_id, pair2->candidate_##dir_2->foundation, pair2->candidate_##dir_2->connection_addr); \
+if ((tsk_striequals(pair2->candidate_##dir_2->foundation, pair->candidate_##dir_2->foundation)) \
+&& (pair2->candidate_##dir_2->comp_id != pair->candidate_##dir_2->comp_id)) { \
+/* nominated = (pair2->state_##dir_2 == tnet_ice_pair_state_succeed); */ \
+nominated = !_tnet_ice_pairs_none_succeed_##dir_2(pairs, pair2->candidate_##dir_2->comp_id, pair2->candidate_##dir_2->foundation); \
+break; \
+} \
+} \
+} \
+\
+if (nominated && (pos++ >= index)) { \
+ret = pair; \
+break; \
+}\
+} \
+} \
+} \
+} \
+
+ // true only if both RTP and RTCP are nominated
+ tsk_bool_t tnet_ice_pairs_have_nominated_offer(const tnet_ice_pairs_L_t* pairs, tsk_bool_t check_rtcp)
+ {
+ const tnet_ice_pair_t *pair_ = tsk_null;
+ tsk_bool_t is_nominated_rtp, is_nominated_rtcp = tsk_true;
+ TNET_ICE_PAIR_DEBUG_INFO("tnet_ice_pairs_have_nominated_offer()");
+ _tnet_ice_pairs_get_nominated_offer_at((pairs), 0, TNET_ICE_CANDIDATE_COMPID_RTP, check_rtcp, (pair_));
+ if((is_nominated_rtp = (pair_ != tsk_null)) && check_rtcp){
+ _tnet_ice_pairs_get_nominated_offer_at((pairs), 0, TNET_ICE_CANDIDATE_COMPID_RTCP, check_rtcp, (pair_));
+ is_nominated_rtcp =(pair_ != tsk_null);
+ }
+ TNET_ICE_PAIR_DEBUG_INFO("is_nominated_rtp_offer=%s, is_nominated_rtcp_offer=%s", is_nominated_rtp?"yes":"no", is_nominated_rtcp?"yes":"no");
+ return (is_nominated_rtp && is_nominated_rtcp);
+ }
+
+ // true only if both RTP and RTCP are nominated
+ tsk_bool_t tnet_ice_pairs_have_nominated_answer(const tnet_ice_pairs_L_t* pairs, tsk_bool_t check_rtcp)
+ {
+ const tnet_ice_pair_t *pair_ = tsk_null;
+ tsk_bool_t is_nominated_rtp, is_nominated_rtcp = tsk_true;
+ TNET_ICE_PAIR_DEBUG_INFO("tnet_ice_pairs_have_nominated_answer()");
+ _tnet_ice_pairs_get_nominated_answer_at((pairs), 0, TNET_ICE_CANDIDATE_COMPID_RTP, check_rtcp, (pair_));
+ if((is_nominated_rtp = (pair_ != tsk_null)) && check_rtcp){
+ _tnet_ice_pairs_get_nominated_answer_at((pairs), 0, TNET_ICE_CANDIDATE_COMPID_RTCP, check_rtcp, (pair_));
+ is_nominated_rtcp =(pair_ != tsk_null);
+ }
+ TNET_ICE_PAIR_DEBUG_INFO("is_nominated_rtp_answer=%s, is_nominated_rtcp_answer=%s", is_nominated_rtp?"yes":"no", is_nominated_rtcp?"yes":"no");
+ return (is_nominated_rtp && is_nominated_rtcp);
+ }
+
+ // true only if both RTP and RTCP are nominated in symetric way
+ tsk_bool_t tnet_ice_pairs_have_nominated_symetric_2(const tnet_ice_pairs_L_t* pairs, tsk_bool_t check_rtcp, tsk_bool_t *got_hosts)
+ {
+ const tnet_ice_candidate_t *candidate_offer, *candidate_answer_src, *candidate_answer_dest;
+ tsk_bool_t is_nominated_rtp, is_nominated_rtcp = tsk_true;
+ int ret;
+
+ if (got_hosts) {
+ *got_hosts = tsk_false;
+ }
+ ret = tnet_ice_pairs_get_nominated_symetric_candidates(pairs, TNET_ICE_CANDIDATE_COMPID_RTP, &candidate_offer, &candidate_answer_src, &candidate_answer_dest);
+ if ((is_nominated_rtp = (ret == 0 && candidate_offer && candidate_answer_src && candidate_answer_dest)) && got_hosts) {
+ *got_hosts = (candidate_offer->type_e == tnet_ice_cand_type_host
+ && candidate_answer_src->type_e == tnet_ice_cand_type_host
+ && candidate_answer_dest->type_e == tnet_ice_cand_type_host);
+ }
+ if(is_nominated_rtp && check_rtcp){
+ ret = tnet_ice_pairs_get_nominated_symetric_candidates(pairs, TNET_ICE_CANDIDATE_COMPID_RTCP, &candidate_offer, &candidate_answer_src, &candidate_answer_dest);
+ if ((is_nominated_rtcp = (ret == 0 && candidate_offer && candidate_answer_src && candidate_answer_dest)) && got_hosts) {
+ *got_hosts &= (candidate_offer->type_e == tnet_ice_cand_type_host
+ && candidate_answer_src->type_e == tnet_ice_cand_type_host
+ && candidate_answer_dest->type_e == tnet_ice_cand_type_host);
+ }
+ }
+ return (is_nominated_rtp && is_nominated_rtcp);
+ }
+
+ // true only if both RTP and RTCP are nominated in symetric way
+ tsk_bool_t tnet_ice_pairs_have_nominated_symetric(const tnet_ice_pairs_L_t* pairs, tsk_bool_t check_rtcp)
+ {
+#define got_hosts tsk_null
+ return tnet_ice_pairs_have_nominated_symetric_2(pairs, check_rtcp, got_hosts);
+ }
+
+ // gets symetric nominated candidates with the highest priority
+ // will succeed only if both RTP and RTCP are ok
+ int tnet_ice_pairs_get_nominated_symetric_candidates(const tnet_ice_pairs_L_t* pairs, uint32_t comp_id,
+ const tnet_ice_candidate_t** candidate_offer,
+ const tnet_ice_candidate_t** candidate_answer_src,
+ const tnet_ice_candidate_t** candidate_answer_dest)
+ {
+ int ret;
+ const tnet_ice_pair_t *pair_offer = tsk_null, *pair_answer_src = tsk_null, *pair_answer_dest = tsk_null;
+ if (!pairs || !candidate_offer || !candidate_answer_src || !candidate_answer_dest) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ *candidate_offer = tsk_null;
+ *candidate_answer_src = tsk_null;
+ *candidate_answer_dest = tsk_null;
+
+ if ((ret = tnet_ice_pairs_get_nominated_symetric_pairs(pairs, comp_id, &pair_offer, &pair_answer_src, &pair_answer_dest)) == 0) {
+ *candidate_offer = pair_offer ? pair_offer->candidate_offer : tsk_null;
+ *candidate_answer_src = pair_answer_src ? pair_answer_src->candidate_answer : tsk_null;
+ *candidate_answer_dest = pair_answer_dest ? pair_answer_dest->candidate_answer : tsk_null;
+ }
+ return ret;
+ }
+
+ int tnet_ice_pairs_get_nominated_symetric_pairs(const tnet_ice_pairs_L_t* pairs, uint32_t comp_id,
+ const struct tnet_ice_pair_s** _pair_offer,
+ const struct tnet_ice_pair_s** _pair_answer_src,
+ const struct tnet_ice_pair_s** _pair_answer_dest)
+ {
+ const tnet_ice_pair_t *pair_offer = tsk_null;
+ const tnet_ice_pair_t *pair_answer = tsk_null;
+ tsk_size_t i_offer, i_answer;
+ static const tsk_bool_t __check_fullness = tsk_false; // pairs will be checked seperatly
+
+ if (!pairs || !_pair_offer || !_pair_answer_src || !_pair_answer_dest) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ *_pair_offer = tsk_null;
+ *_pair_answer_src = tsk_null;
+ *_pair_answer_dest = tsk_null;
+
+ i_offer = 0;
+ while (1) {
+ _tnet_ice_pairs_get_nominated_offer_at((pairs), i_offer, comp_id, __check_fullness, (pair_offer)); // pair with socket SO as sender
+ if(!pair_offer) return 0;
+ ++i_offer;
+ if (pair_offer->candidate_offer->comp_id != comp_id) continue;
+ // find another pair with socket SO as receiver
+
+ i_answer = 0;
+ while (1) {
+ _tnet_ice_pairs_get_nominated_answer_at((pairs), i_answer, comp_id, __check_fullness, (pair_answer));
+ if (!pair_answer) break;
+ ++i_answer;
+ if (pair_answer->candidate_offer->comp_id != comp_id) continue;
+ if (pair_answer->candidate_offer == pair_offer->candidate_offer) {
+ *_pair_offer = pair_offer;
+ *_pair_answer_src = pair_answer;
+ *_pair_answer_dest = pair_offer;
+ return 0;
+ }
+ }
+ }
+ return 0;
+
+ }
diff --git a/tinyNET/src/ice/tnet_ice_pair.h b/tinyNET/src/ice/tnet_ice_pair.h
new file mode 100644
index 0000000..7e40eb8
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice_pair.h
@@ -0,0 +1,86 @@
+/*
+* Copyright (C) 2012-2014 Mamadou DIOP
+* Copyright (C) 2012-2014 Doubango Telecom <http://www.doubango.org>.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+#ifndef TNET_ICE_PAIR_H
+#define TNET_ICE_PAIR_H
+
+#include "tinynet_config.h"
+
+#include "tnet_types.h"
+#include "stun/tnet_stun_types.h"
+
+#include "tsk_list.h"
+
+typedef tsk_list_t tnet_ice_pairs_L_t;
+
+struct tnet_ice_candidate_s;
+
+typedef enum tnet_ice_pair_state_e
+{
+ tnet_ice_pair_state_frozen,
+ tnet_ice_pair_state_waiting,
+ tnet_ice_pair_state_in_progress,
+ tnet_ice_pair_state_succeed,
+ tnet_ice_pair_state_failed
+}
+tnet_ice_pair_state_t;
+
+typedef struct tnet_ice_pair_s
+{
+ TSK_DECLARE_OBJECT;
+
+ uint64_t id;
+ uint64_t priority;
+ tnet_ice_pair_state_t state_offer;
+ tnet_ice_pair_state_t state_answer;
+ tsk_bool_t is_ice_jingle;
+ tsk_bool_t is_controlling;
+ tsk_bool_t is_nominated;
+ uint64_t tie_breaker;
+ struct tnet_ice_candidate_s* candidate_offer;
+ struct tnet_ice_candidate_s* candidate_answer;
+ struct tnet_stun_pkt_s* last_request;
+ struct sockaddr_storage remote_addr;
+ tnet_turn_peer_id_t turn_peer_id;
+}
+tnet_ice_pair_t;
+
+tnet_ice_pair_t* tnet_ice_pair_create(const struct tnet_ice_candidate_s* candidate_offer, const struct tnet_ice_candidate_s* candidate_answer, tsk_bool_t is_controlling, uint64_t tie_breaker, tsk_bool_t is_ice_jingle);
+tnet_ice_pair_t* tnet_ice_pair_prflx_create(tnet_ice_pairs_L_t* pairs, tnet_fd_t local_fd, const struct sockaddr_storage *remote_addr);
+int tnet_ice_pair_send_conncheck(tnet_ice_pair_t *self);
+int tnet_ice_pair_send_response(tnet_ice_pair_t *self, const struct tnet_stun_pkt_s* request, const short code, const char* phrase, const struct sockaddr_storage *remote_addr);
+int tnet_ice_pair_auth_conncheck(const tnet_ice_pair_t *self, const struct tnet_stun_pkt_s* request, const void* request_buff, tsk_size_t request_buff_size, short* resp_code, char** resp_phrase);
+int tnet_ice_pair_recv_response(tnet_ice_pair_t *self, const struct tnet_stun_pkt_s* response, tsk_bool_t is_4conncheck);
+const tnet_ice_pair_t* tnet_ice_pairs_find_by_response(tnet_ice_pairs_L_t* pairs, const struct tnet_stun_pkt_s* response);
+const tnet_ice_pair_t* tnet_ice_pairs_find_by_fd_and_addr(tnet_ice_pairs_L_t* pairs, tnet_fd_t local_fd, const struct sockaddr_storage *remote_addr);
+tsk_bool_t tnet_ice_pairs_have_nominated_offer(const tnet_ice_pairs_L_t* pairs, tsk_bool_t check_rtcp);
+tsk_bool_t tnet_ice_pairs_have_nominated_answer(const tnet_ice_pairs_L_t* pairs, tsk_bool_t check_rtcp);
+tsk_bool_t tnet_ice_pairs_have_nominated_symetric(const tnet_ice_pairs_L_t* pairs, tsk_bool_t check_rtcp);
+tsk_bool_t tnet_ice_pairs_have_nominated_symetric_2(const tnet_ice_pairs_L_t* pairs, tsk_bool_t check_rtcp, tsk_bool_t *got_hosts);
+int tnet_ice_pairs_get_nominated_symetric_candidates(const tnet_ice_pairs_L_t* pairs, uint32_t comp_id,
+ const struct tnet_ice_candidate_s** candidate_offer,
+ const struct tnet_ice_candidate_s** candidate_answer_src,
+ const struct tnet_ice_candidate_s** candidate_answer_dest);
+int tnet_ice_pairs_get_nominated_symetric_pairs(const tnet_ice_pairs_L_t* pairs, uint32_t comp_id,
+ const struct tnet_ice_pair_s** pair_offer,
+ const struct tnet_ice_pair_s** pair_answer_src,
+ const struct tnet_ice_pair_s** pair_answer_dest);
+
+#endif /* TNET_ICE_PAIR_H */
diff --git a/tinyNET/src/ice/tnet_ice_utils.c b/tinyNET/src/ice/tnet_ice_utils.c
new file mode 100644
index 0000000..d4ba8a7
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice_utils.c
@@ -0,0 +1,160 @@
+/*
+* Copyright (C) 2012-2014 Mamadou DIOP
+* Copyright (C) 2012-2014 Doubango Telecom <http://www.doubango.org>.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+#include "tnet_ice_utils.h"
+#include "tnet_ice_candidate.h"
+#include "tnet_socket.h"
+
+#include "tsk_time.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h>
+
+static const char ice_chars[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'k', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'K', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ '0','1', '2', '3', '4', '5', '6', '7', '8', '9'}; // /!\do not add '/' and '+' because of WebRTC password
+static const tsk_size_t ice_chars_count = sizeof(ice_chars);
+
+uint32_t tnet_ice_utils_get_priority(tnet_ice_cand_type_t type, uint16_t local_pref, tsk_bool_t is_rtp)
+{
+ uint32_t pref;
+ switch(type){
+ case tnet_ice_cand_type_host: pref = TNET_ICE_CANDIDATE_PREF_HOST; break;
+ case tnet_ice_cand_type_srflx: pref = TNET_ICE_CANDIDATE_PREF_SRFLX; break;
+ case tnet_ice_cand_type_prflx: pref = TNET_ICE_CANDIDATE_PREF_PRFLX; break;
+ case tnet_ice_cand_type_relay: default: pref = TNET_ICE_CANDIDATE_PREF_RELAY; break;
+ }
+ return (pref << 24) +
+ (local_pref << 8) +
+ ((256 - (is_rtp ? TNET_ICE_CANDIDATE_COMPID_RTP : TNET_ICE_CANDIDATE_COMPID_RTCP)) << 0);
+}
+
+
+int tnet_ice_utils_compute_foundation(char* foundation, tsk_size_t size)
+{
+
+ tsk_size_t i;
+
+ if(!foundation || !size){
+ TSK_DEBUG_ERROR("Invalid argument");
+ return -1;
+ }
+ for(
+ i = 0; i < size; ++i){
+ foundation[i] = ice_chars[(rand() ^ rand()) % ice_chars_count];
+ }
+
+ return 0;
+}
+
+int tnet_ice_utils_create_sockets(tnet_socket_type_t socket_type, const char* local_ip, tnet_socket_t** socket_rtp, tnet_socket_t** socket_rtcp)
+{
+ tsk_bool_t look4_rtp = (socket_rtp != tsk_null);
+ tsk_bool_t look4_rtcp = (socket_rtcp != tsk_null);
+ uint8_t retry_count = 10;
+ tnet_port_t local_port;
+ static const uint64_t port_range_start = 1024;
+ static const uint64_t port_range_stop = (65535 - 1/* to be sure rtcp port will be valid */);
+ static uint64_t counter = 0;
+
+ /* Creates local rtp and rtcp sockets */
+ while(retry_count--){
+ if(look4_rtp && look4_rtcp){
+ tnet_socket_t* socket_fake = tnet_socket_create(local_ip, TNET_SOCKET_PORT_ANY, socket_type);
+ if(!socket_fake){
+ continue;
+ }
+ if(!(socket_fake->port & 0x01)){ // even number ?
+ *socket_rtp = socket_fake;
+ }
+ else{
+ *socket_rtcp = socket_fake;
+ }
+ local_port = (socket_fake->port & ~1);
+ }
+ else{
+ local_port = (tnet_port_t)((((tsk_time_epoch() + rand() ) ^ ++counter) % (port_range_stop - port_range_start)) + port_range_start);
+ local_port = (local_port & 0xFFFE); /* turn to even number */
+ }
+
+ /* beacuse failure will cause errors in the log, print a message to alert that there is
+ * nothing to worry about */
+ TSK_DEBUG_INFO("RTP/RTCP manager[Begin]: Trying to bind to random ports [%s:%d]", local_ip, local_port);
+
+ if(look4_rtp){
+ if(!*socket_rtp && !(*socket_rtp = tnet_socket_create(local_ip, local_port, socket_type))){
+ TSK_DEBUG_INFO("Failed to bind to %d", local_port);
+ continue;
+ }
+ }
+
+ if(look4_rtcp){
+ if(!*socket_rtcp && !(*socket_rtcp = tnet_socket_create(local_ip, (local_port + 1), socket_type))){
+ TSK_DEBUG_INFO("Failed to bind to %d", (local_port + 1));
+ if(look4_rtp){
+ TSK_OBJECT_SAFE_FREE((*socket_rtp));
+ }
+ continue;
+ }
+ }
+
+ TSK_DEBUG_INFO("RTP/RTCP manager[End]: Trying to bind to random ports");
+ return 0;
+ }
+
+ TSK_DEBUG_ERROR("Failed to bind sockets");
+ return -1;
+}
+
+int tnet_ice_utils_set_ufrag(char** ufrag)
+{
+ if(ufrag){
+ char tmp[16]; int i;
+ for(i = 0; i < (sizeof(tmp)/sizeof(tmp[0])) - 1; ++i){
+ tmp[i] = ice_chars[(rand() ^ rand()) % ice_chars_count];
+ }
+ tmp[i] = '\0';
+ tsk_strupdate(ufrag, tmp);
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+}
+
+int tnet_ice_utils_set_pwd(char** pwd)
+{
+ if(pwd){
+ char tmp[23]; int i;
+ for(i = 0; i < (sizeof(tmp)/sizeof(tmp[0])) - 1; ++i){
+ tmp[i] = ice_chars[(rand() ^ rand()) % ice_chars_count];
+ }
+ tmp[i] = '\0';
+ tsk_strupdate(pwd, tmp);
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+} \ No newline at end of file
diff --git a/tinyNET/src/ice/tnet_ice_utils.h b/tinyNET/src/ice/tnet_ice_utils.h
new file mode 100644
index 0000000..8e53915
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice_utils.h
@@ -0,0 +1,42 @@
+/*
+* Copyright (C) 2012-2014 Mamadou DIOP
+* Copyright (C) 2012-2014 Doubango Telecom <http://www.doubango.org>.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+#ifndef TNET_ICE_UTILS_H
+#define TNET_ICE_UTILS_H
+
+#include "tinynet_config.h"
+
+#include "tsk_common.h"
+
+enum tnet_ice_cand_type_e;
+enum tnet_socket_type_e;
+enum tnet_stun_addr_family_e;
+struct tnet_socket_s;
+
+
+uint32_t tnet_ice_utils_get_priority(enum tnet_ice_cand_type_e type, uint16_t local_pref, tsk_bool_t is_rtp);
+int tnet_ice_utils_compute_foundation(char* foundation, tsk_size_t size);
+int tnet_ice_utils_create_sockets(enum tnet_socket_type_e socket_type, const char* local_ip, struct tnet_socket_s** socket_rtp, struct tnet_socket_s** socket_rtcp);
+int tnet_ice_utils_set_ufrag(char** ufrag);
+int tnet_ice_utils_set_pwd(char** pwd);
+
+
+#endif /* TNET_ICE_UTILS_H */
diff --git a/tinyNET/src/stun/AStyle.sh b/tinyNET/src/stun/AStyle.sh
new file mode 100644
index 0000000..9d81f4d
--- /dev/null
+++ b/tinyNET/src/stun/AStyle.sh
@@ -0,0 +1 @@
+../../../thirdparties/win32/bin/AStyle.exe --style=k/r --lineend=linux --mode=c --add-brackets --break-closing-brackets --recursive "*.c" "*.h" \ No newline at end of file
diff --git a/tinyNET/src/stun/tnet_stun.c b/tinyNET/src/stun/tnet_stun.c
new file mode 100644
index 0000000..d8566b2
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun.c
@@ -0,0 +1,440 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_stun.c
+// * @brief Session Traversal Utilities for NAT (STUN) implementation as per RFC 5389 and RFC 3489(Obsolete).
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#include "tnet_stun.h"
+//
+//#include "../tnet_nat.h"
+//#include "../tnet_utils.h"
+//
+//#include "tsk_md5.h"
+//#include "tsk_string.h"
+//#include "tsk_memory.h"
+//#include "tsk_buffer.h"
+//#include "tsk_debug.h"
+//
+//#include <string.h>
+//
+///**@defgroup tnet_stun_group STUN2 (RFC 5389) implementation.
+//*/
+//
+//
+///**@ingroup tnet_stun_group
+//* Creates new @ref tnet_stun_binding_t object.
+//*/
+//tnet_stun_binding_t* tnet_stun_binding_create(tnet_fd_t fd, tnet_socket_type_t socket_type, const char* server_address, tnet_port_t server_port, const char* username, const char* password)
+//{
+// return tsk_object_new(tnet_stun_binding_def_t, fd, socket_type, server_address, server_port, username, password);
+//}
+//
+///**@ingroup tnet_stun_group
+// *
+// * Create generic STUN2 request with all mandatory headers and attributes.
+// *
+// * @param [in,out] binding The binding object from which to create the request.
+// *
+// * @retval STUN2 request if succeed and NULL otherwise.
+//**/
+//tnet_stun_pkt_t *tnet_stun_create_request(const tnet_stun_binding_t* binding)
+//{
+// tnet_stun_pkt_t *message = tnet_stun_message_create(binding->username, binding->password);
+//
+// if(message) {
+// message->realm = tsk_strdup(binding->realm);
+// message->nonce = tsk_strdup(binding->nonce);
+//
+// /* Set the request type (RFC 5389 defines only one type) */
+// message->type = stun_binding_request;
+//
+// { /* Create random transaction id */
+// tsk_istr_t random;
+// tsk_md5digest_t digest;
+//
+// tsk_strrandom(&random);
+// TSK_MD5_DIGEST_CALC(random, sizeof(random), digest);
+//
+// memcpy(message->transac_id, digest, TNET_STUN_TRANSACID_SIZE);
+// }
+//
+// /* Add software attribute */
+// if(binding->software) {
+// tnet_stun_attr_t* attribute = (tnet_stun_attr_t*)tnet_stun_attribute_software_create(binding->software, tsk_strlen(binding->software));
+// tnet_stun_message_add_attribute(message, &attribute);
+// }
+// }
+//
+// return message;
+//}
+//
+//int tnet_stun_send_reliably(const tnet_stun_pkt_t* message)
+//{
+// return -1;
+//}
+//
+//
+///**@ingroup tnet_stun_group
+// *
+// * Internal function to send a STUN message using unrealiable protocol such as UDP.
+// *
+// *
+// * @param localFD The local file descriptor.
+// * @param RTO The Retransmission TimeOut.
+// * @param Rc The Number of retransmissions.
+// * @param [in,out] message The message to send.
+// * @param [in,out] server The destination STUN server.
+// *
+// * @return The response from the server or NULL if transport error.
+//**/
+//tnet_stun_pkt_resp_t* tnet_stun_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const tnet_stun_pkt_t* message, struct sockaddr* server)
+//{
+// /* RFC 5389 - 7.2.1. Sending over UDP
+// STUN indications are not retransmitted; thus, indication transactions over UDP
+// are not reliable.
+// */
+// //int retransmit = (message->type == stun_binding_request);
+//
+// int ret = -1;
+// uint16_t i, rto = RTO;
+// struct timeval tv;
+// fd_set set;
+//
+// tsk_buffer_t *buffer = tnet_stun_pkt_serialize(message);
+// tnet_stun_pkt_resp_t *response = tsk_null;
+//
+// if(!buffer) {
+// goto bail;
+// }
+//
+// {
+////#ifndef SIO_UDP_CONNRESET
+////# ifndef IOC_VENDOR
+////# define IOC_VENDOR 0x18000000
+////# endif
+////# ifndef _WSAIOW
+////# define _WSAIOW(x,y) (IOC_IN|(x)|(y))
+////# endif
+////# define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
+////#endif
+//// DWORD dwBytesReturned = 0;
+//// BOOL bNewBehavior = TRUE;
+//// DWORD status;
+////
+//// // disable new behavior using
+//// // IOCTL: SIO_UDP_CONNRESET
+//// status = WSAIoctl(localFD, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior),
+//// NULL, 0, &dwBytesReturned, NULL, NULL);
+// }
+//
+// tv.tv_sec = 0;
+// tv.tv_usec = 0;
+//
+// /* RFC 5389 - 7.2.1. Sending over UDP
+// A client SHOULD retransmit a STUN request message starting with an
+// interval of RTO ("Retransmission TimeOut"), doubling after each
+// retransmission.
+//
+// e.g. 0 ms, 500 ms, 1500 ms, 3500 ms, 7500ms, 15500 ms, and 31500 ms
+// */
+// for(i=0; i<Rc; i++) {
+// tv.tv_sec += rto/1000;
+// tv.tv_usec += (rto% 1000) * 1000;
+//
+// FD_ZERO(&set);
+// FD_SET(localFD, &set);
+//
+// ret = tnet_sockfd_sendto(localFD, server, buffer->data, buffer->size);
+//
+// if((ret = select(localFD+1, &set, NULL, NULL, &tv))<0) {
+// goto bail;
+// }
+// else if(ret == 0) {
+// /* timeout */
+// TSK_DEBUG_INFO("STUN request timedout at %d", i);
+// rto *= 2;
+// continue;
+// }
+// else if(FD_ISSET(localFD, &set)) {
+// /* there is data to read */
+//
+// tsk_size_t len = 0;
+// void* data = 0;
+//
+// TSK_DEBUG_INFO("STUN request got response");
+//
+// /* Check how how many bytes are pending */
+// if((ret = tnet_ioctlt(localFD, FIONREAD, &len))<0) {
+// goto bail;
+// }
+//
+// if(len==0) {
+// TSK_DEBUG_INFO("tnet_ioctlt() returent zero bytes");
+// continue;
+// }
+//
+// /* Receive pending data */
+// data = tsk_calloc(len, sizeof(uint8_t));
+// if((ret = tnet_sockfd_recvfrom(localFD, data, len, 0, server))<0) {
+// TSK_FREE(data);
+//
+// TSK_DEBUG_ERROR("Recving STUN dgrams failed with error code:%d", tnet_geterrno());
+// goto bail;
+// }
+//
+// /* Parse the incoming response. */
+// response = tnet_stun_message_deserialize(data, (tsk_size_t)ret);
+// TSK_FREE(data);
+//
+// if(response) {
+// if(tnet_stun_transacid_cmp(message->transac_id, response->transac_id)) {
+// /* Not same transaction id */
+// TSK_OBJECT_SAFE_FREE(response);
+// continue;
+// }
+// }
+//
+// goto bail;
+// }
+// else {
+// continue;
+// }
+// }
+//
+//bail:
+// TSK_OBJECT_SAFE_FREE(buffer);
+//
+// return response;
+//}
+//
+///**@ingroup tnet_stun_group
+// * Internal function to send a STUN2 binding request over the network.
+// *
+// * @param [in,out] context The NAT context holding the user preferences.
+// * @param [in,out] binding The STUN binding object used to create the message to send.
+// *
+// * @return Zero if succeed and non-zero error code otherwise.
+//**/
+//int tnet_stun_send_bind(const tnet_nat_context_t* context, tnet_stun_binding_t *binding)
+//{
+// int ret = -1;
+// tnet_stun_pkt_resp_t *response = 0;
+// tnet_stun_pkt_req_t *request = 0;
+//
+//
+// goto stun_phase0;
+//
+// /* RFC 5389 - 10.2.1.1. First Request
+// If the client has not completed a successful request/response
+// transaction with the server (as identified by hostname, if the DNS
+// procedures of Section 9 are used, else IP address if not), it SHOULD
+// omit the USERNAME, MESSAGE-INTEGRITY, REALM, and NONCE attributes.
+// In other words, the very first request is sent as if there were no
+// authentication or message integrity applied.
+// */
+//stun_phase0: {
+// if(!(request = tnet_stun_create_request(binding))) {
+// goto bail;
+// }
+//
+// if(TNET_SOCKET_TYPE_IS_DGRAM(context->socket_type)) {
+// response = tnet_stun_send_unreliably(binding->localFD, context->RTO, context->Rc, request, (struct sockaddr*)&binding->server);
+// }
+//
+// if(response) {
+// if(TNET_STUN_PKT_RESP_IS_ERROR(response)) {
+// short code = tnet_stun_message_get_errorcode(response);
+// const char* realm = tnet_stun_message_get_realm(response);
+// const char* nonce = tnet_stun_message_get_nonce(response);
+//
+// if(code == 401 && realm && nonce) {
+// if(!binding->nonce) {
+// /* First time we get a nonce */
+// tsk_strupdate(&binding->nonce, nonce);
+// tsk_strupdate(&binding->realm, realm);
+//
+// /* Delete the message and response before retrying*/
+// TSK_OBJECT_SAFE_FREE(response);
+// TSK_OBJECT_SAFE_FREE(request);
+//
+// // Send again using new transaction identifier
+// return tnet_stun_send_bind(context, binding);
+// }
+// else {
+// ret = -3;
+// }
+// }
+// else {
+// ret = -2;
+// }
+// }
+// else {
+// const tnet_stun_attr_t *attribute;
+// if((attribute= tnet_stun_message_get_attribute(response, stun_xor_mapped_address))) {
+// ret = 0;
+// binding->xmaddr = tsk_object_ref((void*)attribute);
+// }
+// else if((attribute= tnet_stun_message_get_attribute(response, stun_mapped_address))) {
+// ret = 0;
+// binding->maddr = tsk_object_ref((void*)attribute);
+// }
+// }
+// }
+// }
+// /* END OF stun_phase0 */
+//
+//bail:
+// TSK_OBJECT_SAFE_FREE(response);
+// TSK_OBJECT_SAFE_FREE(request);
+//
+// return ret;
+//}
+//
+///**@ingroup tnet_stun_group
+// *
+// * Public function to create a binding context.
+// *
+// * @param [in,out] nat_context The NAT context.
+// * @param localFD The local file descriptor for which to create the binding context.
+// *
+// * @return A valid binding id if succeed and @ref kStunBindingInvalidId otherwise. If the returned id is valid then
+// * the newly created binding will contain the server reflexive address associated to the local file descriptor.
+//**/
+//tnet_stun_binding_id_t tnet_stun_bind(const tnet_nat_context_t* nat_context, tnet_fd_t localFD)
+//{
+// tnet_stun_binding_id_t id = kStunBindingInvalidId;
+//
+// tnet_stun_binding_t *binding = 0;
+//
+// if(nat_context && localFD != TNET_INVALID_FD) {
+// if(!(binding = tnet_stun_binding_create(localFD, nat_context->socket_type, nat_context->server_address, nat_context->server_port, nat_context->username, nat_context->password))) {
+// goto bail;
+// }
+//
+// if(tnet_stun_send_bind(nat_context, binding)) {
+// TSK_OBJECT_SAFE_FREE(binding);
+// goto bail;
+// }
+//
+// id = binding->id;
+// tsk_list_push_back_data(nat_context->stun_bindings, (void**)&binding);
+// }
+//
+//bail:
+// return id;
+//}
+//
+///**@ingroup tnet_stun_group
+// * Compares two transaction ids.
+// *
+// * @param id1 The first transaction identifier.
+// * @param id2 The second transaction identifier.
+// *
+// * @return Zero if the two identifiers are equal and non-zero value otherwise.
+//**/
+//int tnet_stun_transacid_cmp(const tnet_stun_transac_id_t id1, const tnet_stun_transac_id_t id2)
+//{
+// tsk_size_t i;
+// for(i=0; i<sizeof(tnet_stun_transac_id_t); i++) {
+// if(id1[i] != id2[i]) {
+// return (id1[i] - id2[i]);
+// }
+// }
+// return 0;
+//}
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+////=================================================================================================
+//// STUN2 BINDING object definition
+////
+//static tsk_object_t* tnet_stun_binding_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_binding_t *binding = self;
+// if(binding) {
+// static tnet_stun_binding_id_t __binding_unique_id = 0;
+//
+// const char* server_address;
+// tnet_port_t server_port;
+//
+// binding->id = ++__binding_unique_id;
+//
+// binding->localFD = va_arg(*app, tnet_fd_t);
+// binding->socket_type = va_arg(*app, tnet_socket_type_t);
+//
+// server_address = tsk_strdup(va_arg(*app, const char*));
+//#if defined(__GNUC__)
+// server_port = (tnet_port_t)va_arg(*app, unsigned);
+//#else
+// server_port = va_arg(*app, tnet_port_t);
+//#endif
+//
+// binding->username = tsk_strdup(va_arg(*app, const char*));
+// binding->password = tsk_strdup(va_arg(*app, const char*));
+//
+// if(server_address) {
+// tnet_sockaddr_init(server_address, server_port, binding->socket_type, &binding->server);
+// }
+//
+// binding->software = tsk_strdup(TNET_SOFTWARE);
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_binding_dtor(tsk_object_t * self)
+//{
+// tnet_stun_binding_t *binding = self;
+// if(binding) {
+// TSK_FREE(binding->username);
+// TSK_FREE(binding->password);
+// TSK_FREE(binding->realm);
+// TSK_FREE(binding->nonce);
+//
+// TSK_FREE(binding->software);
+//
+// TSK_OBJECT_SAFE_FREE(binding->maddr);
+// TSK_OBJECT_SAFE_FREE(binding->xmaddr);
+// }
+//
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_binding_def_s = {
+// sizeof(tnet_stun_binding_t),
+// tnet_stun_binding_ctor,
+// tnet_stun_binding_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_binding_def_t = &tnet_stun_binding_def_s;
+//
+//
diff --git a/tinyNET/src/stun/tnet_stun.h b/tinyNET/src/stun/tnet_stun.h
new file mode 100644
index 0000000..26f0def
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun.h
@@ -0,0 +1,127 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_stun.h
+// * @brief Session Traversal Utilities for NAT (STUN) implementation as per RFC 5389 and RFC 3489(Obsolete).
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#ifndef TNET_STUN_H
+//#define TNET_STUN_H
+//
+//#include "tinynet_config.h"
+//#include "stun/tnet_stun_message.h"
+//#include "tnet_types.h"
+//#include "tnet_socket.h"
+//
+//#include "tsk_object.h"
+//
+//TNET_BEGIN_DECLS
+//
+///**@ingroup tnet_stun_group
+//*/
+////typedef uint64_t tnet_stun_binding_id_t;
+///**@ingroup tnet_stun_group
+// * @def kStunBindingInvalidId
+// * STUN2 invalid binding id.
+//**/
+///**@ingroup tnet_stun_group
+// * @def TNET_STUN_IS_VALID_BINDING_ID
+// * Checks the validity of the STUN @a id.
+//**/
+//#define kStunBindingInvalidId 0
+//#define TNET_STUN_IS_VALID_BINDING_ID(id) (id != kStunBindingInvalidId)
+//
+///**@ingroup tnet_stun_group
+// * Default port for both TCP and UDP protos as per RFC 5389 subclause 9.
+//**/
+//#define TNET_STUN_TCP_UDP_DEFAULT_PORT 3478
+//
+///**@ingroup tnet_stun_group
+// * Default port for TLS protocol as per RFC 5389 subclause 9.
+//**/
+//#define TNET_STUN_TLS_DEFAULT_PORT 5349
+//
+//
+///**@ingroup tnet_stun_group
+// * STUN2 magic cookie value in network byte order as per RFC 5389 subclause 6.
+//**/
+//#define kStunMagicCookieLong 0x2112A442
+//
+///**@ingroup tnet_stun_group
+// * STUN2 header size as per RFC 5389 subclause 6.
+//**/
+//#define kStunAttrHdrSizeInOctets 20
+//
+///**@ingroup tnet_stun_group
+// * STUN2 binding context.
+//**/
+//typedef struct tnet_stun_binding_s {
+// TSK_DECLARE_OBJECT;
+//
+// //! A unique id to identify this binding.
+// tnet_stun_binding_id_t id;
+//
+// //! The username to authenticate to the STUN server.
+// char* username;
+// //! The password to authenticate to the STUN server.
+// char* password;
+// //! The realm.
+// char* realm;
+// //! The nonce.
+// char* nonce;
+// //! The client name.
+// char* software;
+// //! Local file descriptor for which to get server reflexive address.
+// tnet_fd_t localFD;
+// //! The type of the bound socket.
+// tnet_socket_type_t socket_type;
+// //! The address of the STUN server.
+// struct sockaddr_storage server;
+// //! Server reflexive address of the local socket(STUN1 as per RFC 3489).
+// tnet_stun_attribute_mapped_addr_t *maddr;
+// //! XORed server reflexive address (STUN2 as per RFC 5389).
+// tnet_stun_attribute_xmapped_addr_t *xmaddr;
+//} tnet_stun_binding_t;
+//
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_binding_def_t;
+///**@ingroup tnet_stun_group
+// * List of @ref tnet_stun_binding_t elements.
+//**/
+//typedef tsk_list_t tnet_stun_bindings_L_t;
+//
+////#if defined(__SYMBIAN32__) || ANDROID /* Forward declaration */
+//struct struct tnet_nat_ctx_s;
+////#endif
+//
+//int tnet_stun_send_reliably(const tnet_stun_pkt_t* message);
+//tnet_stun_pkt_resp_t* tnet_stun_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const tnet_stun_pkt_t* message, struct sockaddr* server);
+//TINYNET_API tnet_stun_binding_id_t tnet_stun_bind(const struct struct tnet_nat_ctx_s* nat_context, tnet_fd_t localFD);
+//int tnet_stun_transacid_cmp(const tnet_stun_transac_id_t id1, const tnet_stun_transac_id_t id2);
+//
+//TNET_END_DECLS
+//
+//
+//#endif /* TNET_STUN_H */
+//
diff --git a/tinyNET/src/stun/tnet_stun_attr.c b/tinyNET/src/stun/tnet_stun_attr.c
new file mode 100644
index 0000000..4c31c05
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_attr.c
@@ -0,0 +1,651 @@
+/* Copyright (C) 2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#include "stun/tnet_stun_attr.h"
+#include "stun/tnet_stun_utils.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#define kWithoutPadding tsk_false
+#define kWithPadding tsk_true
+
+#if !defined(PRINT_DESTROYED_MSG)
+# define PRINT_DESTROYED_MSG 0
+#endif
+
+#define ALIGN_ON_32BITS(size_in_octes) if (((size_in_octes) & 3)) (size_in_octes) += (4 - ((size_in_octes) & 3));
+#define ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(p_buffer, size_in_octes) \
+ if (((size_in_octes) & 3)) { \
+ int c = (4 - ((size_in_octes) & 3)); \
+ memset(p_buffer, 0, c); \
+ (size_in_octes) += c; \
+ }
+
+#define IS_ADDRESS_XOR(e_type) \
+ (e_type == tnet_stun_attr_type_xor_mapped_address || e_type == tnet_stun_attr_type_xor_peer_address || e_type == tnet_stun_attr_type_xor_relayed_address)
+#define IS_VDATA_UINT8(e_type) \
+ (e_type == tnet_stun_attr_type_requested_transport)
+#define IS_VDATA_UINT16(e_type) \
+ (e_type == tnet_stun_attr_type_channel_number)
+#define IS_VDATA_UINT32(e_type) \
+ (e_type == tnet_stun_attr_type_fingerprint || e_type == tnet_stun_attr_type_lifetime || e_type == tnet_stun_attr_type_ice_priority || e_type == tnet_stun_attr_type_connection_id)
+#define IS_VDATA_UINT64(e_type) \
+ (e_type == tnet_stun_attr_type_ice_controlled || e_type == tnet_stun_attr_type_ice_controlling)
+
+static int _tnet_stun_attr_cmp(const tsk_object_t *_att1, const tsk_object_t *_att2)
+{
+ const tnet_stun_attr_t *pc_att1 = (const tnet_stun_attr_t *)_att1;
+ const tnet_stun_attr_t *pc_att2 = (const tnet_stun_attr_t *)_att2;
+
+ return (int)(pc_att1 - pc_att2);
+}
+
+static int _tnet_stun_attr_get_size_in_octetunits(const tnet_stun_attr_t* pc_self, tsk_bool_t with_padding, tsk_size_t* p_size)
+{
+ if (!pc_self || !p_size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ switch (pc_self->hdr.e_type) {
+ case tnet_stun_attr_type_mapped_address:
+ case tnet_stun_attr_type_alternate_server:
+ case tnet_stun_attr_type_xor_mapped_address:
+ case tnet_stun_attr_type_xor_peer_address:
+ case tnet_stun_attr_type_xor_relayed_address: {
+ extern const tsk_object_def_t *tnet_stun_attr_address_def_t;
+ const tnet_stun_attr_address_t* _pc_self = (const tnet_stun_attr_address_t*)pc_self;
+ if (pc_self->__def__ != tnet_stun_attr_address_def_t) {
+ TSK_DEBUG_ERROR("Invalid base type");
+ return -2;
+ }
+ *p_size = (kStunAttrHdrSizeInOctets + 1/*Ignored*/ + 1/*Family*/ + 2/*Port*/ + ((_pc_self->e_family == tnet_stun_address_family_ipv6) ? 16 : 4));
+ if (with_padding) {
+ ALIGN_ON_32BITS(*p_size);
+ }
+ return 0;
+ }
+ case tnet_stun_attr_type_data:
+ case tnet_stun_attr_type_unknown_attrs:
+ case tnet_stun_attr_type_dont_fragment:
+ case tnet_stun_attr_type_software:
+ case tnet_stun_attr_type_nonce:
+ case tnet_stun_attr_type_realm:
+ case tnet_stun_attr_type_username:
+ case tnet_stun_attr_type_password:
+ case tnet_stun_attr_type_channel_number:
+ case tnet_stun_attr_type_message_integrity:
+ case tnet_stun_attr_type_fingerprint:
+ case tnet_stun_attr_type_lifetime:
+ case tnet_stun_attr_type_requested_transport:
+ case tnet_stun_attr_type_ice_use_candidate:
+ case tnet_stun_attr_type_ice_priority:
+ case tnet_stun_attr_type_ice_controlled:
+ case tnet_stun_attr_type_ice_controlling:
+ case tnet_stun_attr_type_connection_id: {
+ extern const tsk_object_def_t *tnet_stun_attr_vdata_def_t;
+ const tnet_stun_attr_vdata_t* _pc_self = (const tnet_stun_attr_vdata_t*)pc_self;
+ if (pc_self->__def__ != tnet_stun_attr_vdata_def_t) {
+ TSK_DEBUG_ERROR("Invalid base type");
+ return -2;
+ }
+ *p_size = (kStunAttrHdrSizeInOctets + _pc_self->u_data_size);
+ if (with_padding) {
+ ALIGN_ON_32BITS(*p_size);
+ }
+ return 0;
+ }
+ case tnet_stun_attr_type_error_code: {
+ const tnet_stun_attr_error_code_t* _pc_self = (const tnet_stun_attr_error_code_t*)pc_self;
+ *p_size = (kStunAttrHdrSizeInOctets + 4 + (tsk_size_t)tsk_strlen(_pc_self->p_reason_phrase));
+ if (with_padding) {
+ ALIGN_ON_32BITS(*p_size);
+ }
+ return 0;
+ }
+ default: {
+ TSK_DEBUG_WARN("Attribute type=%d is unknown. Don't be surprised if something goes wrong.", pc_self->hdr.e_type);
+ *p_size = (kStunAttrHdrSizeInOctets + pc_self->hdr.u_length);
+ if (with_padding) {
+ ALIGN_ON_32BITS(*p_size);
+ }
+ return 0;
+ }
+ }
+}
+
+static int _tnet_stun_attr_write(const tnet_stun_transac_id_t* pc_transac_id, const tnet_stun_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t with_padding, tsk_size_t *p_written)
+{
+ tsk_size_t n_min_req_size;
+ int ret;
+ if (!pc_self || !p_buff_ptr || !n_buff_size || !p_written) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = _tnet_stun_attr_get_size_in_octetunits(pc_self, with_padding, &n_min_req_size))) {
+ return ret;
+ }
+ if (n_min_req_size > n_buff_size) {
+ TSK_DEBUG_ERROR("Buffer too short %u<%u", (unsigned)n_buff_size, (unsigned)n_min_req_size);
+ return -2;
+ }
+
+ *((uint16_t*)&p_buff_ptr[0]) = tnet_htons((unsigned short)pc_self->hdr.e_type);
+ // *((uint16_t*)&p_buff_ptr[2]) = tnet_htons((unsigned short)pc_self->hdr.u_length);
+ *p_written = kStunAttrHdrSizeInOctets;
+
+ switch (pc_self->hdr.e_type) {
+ case tnet_stun_attr_type_mapped_address:
+ case tnet_stun_attr_type_alternate_server:
+ case tnet_stun_attr_type_xor_mapped_address:
+ case tnet_stun_attr_type_xor_peer_address:
+ case tnet_stun_attr_type_xor_relayed_address: {
+ tsk_size_t u_addr_size;
+ extern const tsk_object_def_t *tnet_stun_attr_address_def_t;
+ const tnet_stun_attr_address_t* _pc_self = (const tnet_stun_attr_address_t*)pc_self;
+ tsk_bool_t b_xor = IS_ADDRESS_XOR(pc_self->hdr.e_type);
+ if (pc_self->__def__ != tnet_stun_attr_address_def_t) {
+ TSK_DEBUG_ERROR("Invalid base type");
+ return -2;
+ }
+ p_buff_ptr[*p_written] = 0x00; // Reserved
+ p_buff_ptr[*p_written + 1] = _pc_self->e_family;
+ u_addr_size = (_pc_self->e_family == tnet_stun_address_family_ipv6 ? 16 : 4);
+ if (b_xor) {
+ tsk_size_t u;
+ *((uint16_t*)&p_buff_ptr[*p_written + 2]) = tnet_htons(_pc_self->u_port ^ kStunMagicCookieShort);
+ *((uint32_t*)&p_buff_ptr[*p_written + 4]) = (uint32_t)tnet_htonl(tnet_ntohl(*((uint32_t*)&_pc_self->address[0])) ^ kStunMagicCookieLong);
+ for (u = 4; u < u_addr_size; u += 4) {
+ if (pc_transac_id) {
+ *((uint32_t*)&p_buff_ptr[*p_written + 4 + u]) = (uint32_t)tnet_htonl(tnet_ntohl(*((uint32_t*)&_pc_self->address[u])) ^ tnet_ntohl(*((uint32_t*)(*pc_transac_id + u - 4))));
+ }
+ else {
+ *((uint32_t*)&p_buff_ptr[*p_written + 4 + u]) = (uint32_t)tnet_htonl(tnet_ntohl(*((uint32_t*)&_pc_self->address[u])) ^ 0);
+ }
+ }
+ }
+ else {
+ *((uint16_t*)&p_buff_ptr[*p_written + 2]) = tnet_htons(_pc_self->u_port);
+ memcpy(&p_buff_ptr[*p_written + 4], _pc_self->address, u_addr_size);
+ }
+
+ *p_written += 4 + u_addr_size;
+ *((uint16_t*)&p_buff_ptr[2]) = tnet_htons((unsigned short)*p_written - kStunAttrHdrSizeInOctets);
+ if (with_padding) {
+ ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written);
+ }
+ return 0;
+ }
+
+ case tnet_stun_attr_type_data:
+ case tnet_stun_attr_type_unknown_attrs:
+ case tnet_stun_attr_type_dont_fragment:
+ case tnet_stun_attr_type_software:
+ case tnet_stun_attr_type_nonce:
+ case tnet_stun_attr_type_realm:
+ case tnet_stun_attr_type_username:
+ case tnet_stun_attr_type_password:
+ case tnet_stun_attr_type_channel_number:
+ case tnet_stun_attr_type_message_integrity:
+ case tnet_stun_attr_type_fingerprint:
+ case tnet_stun_attr_type_lifetime:
+ case tnet_stun_attr_type_requested_transport:
+ case tnet_stun_attr_type_ice_use_candidate:
+ case tnet_stun_attr_type_ice_priority:
+ case tnet_stun_attr_type_ice_controlled:
+ case tnet_stun_attr_type_ice_controlling:
+ case tnet_stun_attr_type_connection_id: {
+ extern const tsk_object_def_t *tnet_stun_attr_vdata_def_t;
+ const tnet_stun_attr_vdata_t* _pc_self = (const tnet_stun_attr_vdata_t*)pc_self;
+ if (pc_self->__def__ != tnet_stun_attr_vdata_def_t) {
+ TSK_DEBUG_ERROR("Invalid base type");
+ return -2;
+ }
+ if (_pc_self->p_data_ptr && _pc_self->u_data_size) {
+ if (IS_VDATA_UINT16(pc_self->hdr.e_type) && _pc_self->u_data_size == 2) {
+ *((uint16_t*)&p_buff_ptr[*p_written]) = tnet_htons_2(&_pc_self->p_data_ptr[0]);
+ }
+ else if (IS_VDATA_UINT32(pc_self->hdr.e_type) && _pc_self->u_data_size == 4) {
+ *((uint32_t*)&p_buff_ptr[*p_written]) = (uint32_t)tnet_htonl_2(&_pc_self->p_data_ptr[0]);
+ }
+ else if (IS_VDATA_UINT64(pc_self->hdr.e_type) && _pc_self->u_data_size == 8) {
+ *((uint32_t*)&p_buff_ptr[*p_written]) = (uint32_t)tnet_htonl_2(&_pc_self->p_data_ptr[0]);
+ *((uint32_t*)&p_buff_ptr[*p_written + 4]) = (uint32_t)tnet_htonl_2(&_pc_self->p_data_ptr[4]);
+ }
+ else if (pc_self->hdr.e_type == tnet_stun_attr_type_unknown_attrs && _pc_self->u_data_size && !(_pc_self->u_data_size & 1)) {
+ uint16_t u;
+ for (u = 0; u < _pc_self->u_data_size; u += 2) {
+ *((uint16_t*)&p_buff_ptr[*p_written + u]) = tnet_htons_2(&_pc_self->p_data_ptr[u]);
+ }
+ }
+ else {
+ memcpy(&p_buff_ptr[*p_written], _pc_self->p_data_ptr, _pc_self->u_data_size);
+ }
+ *p_written += _pc_self->u_data_size;
+ }
+ if (with_padding) {
+ ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written);
+ }
+ *((uint16_t*)&p_buff_ptr[2]) = tnet_htons((unsigned short)*p_written - kStunAttrHdrSizeInOctets);
+ return 0;
+ }
+ case tnet_stun_attr_type_error_code: {
+ const tnet_stun_attr_error_code_t* _pc_self = (const tnet_stun_attr_error_code_t*)pc_self;
+ *((uint32_t*)&p_buff_ptr[*p_written]) = (uint32_t)tnet_htonl(((_pc_self->u_class & 0x07) << 8) | _pc_self->u_number);
+ if (_pc_self->p_reason_phrase) {
+ memcpy(&p_buff_ptr[*p_written + 4], _pc_self->p_reason_phrase, tsk_strlen(_pc_self->p_reason_phrase));
+ }
+ *p_written += 4 + tsk_strlen(_pc_self->p_reason_phrase);
+ if (with_padding) {
+ ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written);
+ }
+ *((uint16_t*)&p_buff_ptr[2]) = tnet_htons((unsigned short)*p_written - kStunAttrHdrSizeInOctets);
+ return 0;
+ }
+ default: {
+ TSK_DEBUG_ERROR("Attribute type=%d is unknown.", pc_self->hdr.e_type);
+ return -2;
+ }
+ }
+}
+
+int tnet_stun_attr_init(tnet_stun_attr_t* p_self, tnet_stun_attr_type_t e_type, uint16_t u_length)
+{
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ p_self->hdr.e_type = e_type;
+ p_self->hdr.u_length = u_length;
+ return 0;
+}
+
+int tnet_stun_attr_get_size_in_octetunits_without_padding(const tnet_stun_attr_t* pc_self, tsk_size_t* p_size)
+{
+ return _tnet_stun_attr_get_size_in_octetunits(pc_self, kWithoutPadding, p_size);
+}
+
+int tnet_stun_attr_get_size_in_octetunits_with_padding(const tnet_stun_attr_t* pc_self, tsk_size_t* p_size)
+{
+ return _tnet_stun_attr_get_size_in_octetunits(pc_self, kWithPadding, p_size);
+}
+
+int tnet_stun_attr_write_without_padding(const tnet_stun_transac_id_t* pc_transac_id, const tnet_stun_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written)
+{
+ return _tnet_stun_attr_write(pc_transac_id, pc_self, p_buff_ptr, n_buff_size, kWithoutPadding, p_written);
+}
+
+int tnet_stun_attr_write_with_padding(const tnet_stun_transac_id_t* pc_transac_id, const tnet_stun_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written)
+{
+ return _tnet_stun_attr_write(pc_transac_id, pc_self, p_buff_ptr, n_buff_size, kWithPadding, p_written);
+}
+
+int tnet_stun_attr_read(const tnet_stun_transac_id_t* pc_transac_id, const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_consumed_octets, tnet_stun_attr_t** pp_attr)
+{
+ tnet_stun_attr_type_t Type;
+ uint16_t Length, PadLength;
+ int ret = -1;
+ static const void* kNullBuffPtr = tsk_null;
+ if (!pc_buff_ptr || !n_buff_size || !pp_attr || !p_consumed_octets) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (n_buff_size < kStunAttrHdrSizeInOctets) {
+ TSK_DEBUG_ERROR("Buffer too short(%u)", (unsigned)n_buff_size);
+ return -2;
+ }
+
+ Type = tnet_ntohs_2(&pc_buff_ptr[0]);
+ Length = tnet_ntohs_2(&pc_buff_ptr[2]);
+ if (Length > n_buff_size) {
+ TSK_DEBUG_ERROR("Buffer too short(%u). Length=%u", (unsigned)n_buff_size, (unsigned)Length);
+ return -3;
+ }
+
+ PadLength = (Length & 0x03) ? (4 - (Length & 0x03)) : 0;
+
+ *pp_attr = tsk_null;
+ *p_consumed_octets = kStunAttrHdrSizeInOctets + Length + PadLength;
+
+ switch (Type) {
+ case tnet_stun_attr_type_mapped_address:
+ case tnet_stun_attr_type_alternate_server:
+ case tnet_stun_attr_type_xor_mapped_address:
+ case tnet_stun_attr_type_xor_peer_address:
+ case tnet_stun_attr_type_xor_relayed_address: {
+ // First 8bits must be ignored
+ tnet_stun_address_family_t e_family = pc_buff_ptr[5];
+ uint16_t u_port = tnet_ntohs_2(&pc_buff_ptr[6]);
+ tnet_stun_attr_address_t* p_attr;
+ tsk_bool_t b_xor = IS_ADDRESS_XOR(Type);
+ uint16_t u, u_addr_size = (e_family == tnet_stun_address_family_ipv6) ? 16 : 4;
+
+ if (b_xor) {
+ u_port ^= kStunMagicCookieShort;
+ }
+ if ((ret = tnet_stun_attr_address_create(Type, e_family, u_port, (const tnet_stun_addr_t*)kNullBuffPtr, &p_attr))) {
+ return ret;
+ }
+ if (b_xor) {
+ *((uint32_t*)&p_attr->address[0]) = (uint32_t)tnet_htonl(tnet_ntohl_2(&pc_buff_ptr[8]) ^ kStunMagicCookieLong);
+ for (u = 4; u < u_addr_size; u += 4) {
+ if (pc_transac_id) {
+ *((uint32_t*)&p_attr->address[u]) = (uint32_t)tnet_htonl(tnet_ntohl_2(&pc_buff_ptr[8 + u]) ^ tnet_ntohl_2(((uint32_t*)(*pc_transac_id + u - 4))));
+ }
+ else {
+ *((uint32_t*)&p_attr->address[u]) = (uint32_t)tnet_htonl(tnet_ntohl_2(&pc_buff_ptr[8 + u]) ^ 0);
+ }
+ }
+ }
+ else {
+ memcpy(p_attr->address, &pc_buff_ptr[8], u_addr_size);
+ }
+ *pp_attr = TNET_STUN_ATTR(p_attr);
+ break;
+ }
+
+ case tnet_stun_attr_type_error_code: {
+ // First 21bits must be ignored
+ uint8_t Class = pc_buff_ptr[6] & 0x07;
+ uint8_t Number = pc_buff_ptr[7] & 0xff;
+ tnet_stun_attr_error_code_t* p_attr;
+ if ((ret = tnet_stun_attr_error_code_create(Class, Number, &pc_buff_ptr[8], (Length - 4), &p_attr))) {
+ return ret;
+ }
+ *pp_attr = TNET_STUN_ATTR(p_attr);
+ break;
+ }
+
+ case tnet_stun_attr_type_data:
+ case tnet_stun_attr_type_unknown_attrs:
+ case tnet_stun_attr_type_dont_fragment:
+ case tnet_stun_attr_type_software:
+ case tnet_stun_attr_type_nonce:
+ case tnet_stun_attr_type_realm:
+ case tnet_stun_attr_type_username:
+ case tnet_stun_attr_type_password:
+ case tnet_stun_attr_type_channel_number:
+ case tnet_stun_attr_type_message_integrity:
+ case tnet_stun_attr_type_fingerprint:
+ case tnet_stun_attr_type_lifetime:
+ case tnet_stun_attr_type_requested_transport:
+ case tnet_stun_attr_type_ice_use_candidate:
+ case tnet_stun_attr_type_ice_priority:
+ case tnet_stun_attr_type_ice_controlled:
+ case tnet_stun_attr_type_ice_controlling:
+ case tnet_stun_attr_type_connection_id:
+ default: {
+ tnet_stun_attr_vdata_t* p_attr;
+ if (IS_VDATA_UINT16(Type) && Length == 2) {
+ uint16_t u16 = tnet_ntohs_2(&pc_buff_ptr[4]);
+ if ((ret = tnet_stun_attr_vdata_create(Type, (uint8_t*)&u16, 2, &p_attr))) {
+ return ret;
+ }
+ }
+ else if (IS_VDATA_UINT32(Type) && Length == 4) {
+ uint32_t u32 = (uint32_t)tnet_ntohl_2(&pc_buff_ptr[4]);
+ if ((ret = tnet_stun_attr_vdata_create(Type, (uint8_t*)&u32, 4, &p_attr))) {
+ return ret;
+ }
+ }
+ else if (IS_VDATA_UINT64(Type) && Length == 8) {
+ uint64_t u64 = ((uint64_t)tnet_ntohl_2(&pc_buff_ptr[4])) << 32;
+ u64 |= tnet_ntohl_2(&pc_buff_ptr[8]);
+ if ((ret = tnet_stun_attr_vdata_create(Type, (uint8_t*)&u64, 8, &p_attr))) {
+ return ret;
+ }
+ }
+ else if (Type == tnet_stun_attr_type_unknown_attrs && Length && !(Length & 1)) {
+ uint16_t u;
+ uint8_t *_p_data_ptr = tsk_malloc(Length);
+ if (!_p_data_ptr) {
+ TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", Length);
+ return -4;
+ }
+ memcpy(_p_data_ptr, &pc_buff_ptr[4], Length);
+ for (u = 0; u < Length; u += 2) {
+ *((uint16_t*)&_p_data_ptr[u]) = tnet_htons_2(&_p_data_ptr[u]);
+ }
+ if ((ret = tnet_stun_attr_vdata_create(Type, _p_data_ptr, Length, &p_attr))) {
+ TSK_FREE(_p_data_ptr);
+ return ret;
+ }
+ TSK_FREE(_p_data_ptr);
+ }
+ else {
+ if ((ret = tnet_stun_attr_vdata_create(Type, &pc_buff_ptr[4], Length, &p_attr))) {
+ return ret;
+ }
+ }
+ *pp_attr = TNET_STUN_ATTR(p_attr);
+ break;
+ }
+ }
+ return ret;
+}
+
+// ============== VDATA (USERNAME, MESSAGE-INTEGRITY, ...) ================ //
+int tnet_stun_attr_vdata_create(tnet_stun_attr_type_t e_type, const uint8_t* pc_data_ptr, uint16_t u_data_size, tnet_stun_attr_vdata_t** pp_attr)
+{
+ int ret = -1;
+ uint16_t u_length = pc_data_ptr ? u_data_size : 0;
+ tnet_stun_attr_vdata_t* p_attr = tsk_null;
+ extern const tsk_object_def_t *tnet_stun_attr_vdata_def_t;
+ if (!pp_attr) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!(p_attr = tsk_object_new(tnet_stun_attr_vdata_def_t))) {
+ ret = -2;
+ goto bail;
+ }
+ if ((ret = tnet_stun_attr_init(TNET_STUN_ATTR(p_attr), e_type, u_length))) {
+ goto bail;
+ }
+ if (u_length) {
+ if (!(p_attr->p_data_ptr = tsk_malloc(u_length + 1))) {
+ ret = -3;
+ goto bail;
+ }
+ memcpy(p_attr->p_data_ptr, pc_data_ptr, u_length);
+ p_attr->u_data_size = u_length;
+ p_attr->p_data_ptr[u_length] = '\0';
+ }
+ *pp_attr = p_attr;
+
+bail:
+ if (ret) {
+ TSK_OBJECT_SAFE_FREE(p_attr);
+ }
+ return ret;
+}
+
+int tnet_stun_attr_vdata_update(tnet_stun_attr_vdata_t* p_self, const uint8_t* pc_data_ptr, uint16_t u_data_size)
+{
+ uint16_t _u_data_size = (pc_data_ptr && u_data_size) ? u_data_size : 0;
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (_u_data_size) {
+ if (!(p_self->p_data_ptr = tsk_realloc(p_self->p_data_ptr, _u_data_size + 1))) {
+ p_self->u_data_size = 0;
+ ((tnet_stun_attr_t*)p_self)->hdr.u_length = 0;
+ return -3;
+ }
+ memcpy(p_self->p_data_ptr, pc_data_ptr, _u_data_size);
+ p_self->p_data_ptr[_u_data_size] = '\0';
+ }
+ else {
+ TSK_FREE(p_self->p_data_ptr);
+ }
+ p_self->u_data_size = _u_data_size;
+ ((tnet_stun_attr_t*)p_self)->hdr.u_length = p_self->u_data_size;
+ return 0;
+}
+
+static tsk_object_t* tnet_stun_attr_vdata_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_stun_attr_vdata_t *p_vdata = (tnet_stun_attr_vdata_t *)self;
+ if (p_vdata) {
+ }
+ return self;
+}
+static tsk_object_t* tnet_stun_attr_vdata_dtor(tsk_object_t * self)
+{
+ tnet_stun_attr_vdata_t *p_vdata = (tnet_stun_attr_vdata_t *)self;
+ if (p_vdata) {
+#if PRINT_DESTROYED_MSG
+ TSK_DEBUG_INFO("*** STUN Attribute(VDATA) destroyed ***");
+#endif
+ TSK_FREE(p_vdata->p_data_ptr);
+ }
+ return self;
+}
+static const tsk_object_def_t tnet_stun_attr_vdata_def_s = {
+ sizeof(tnet_stun_attr_vdata_t),
+ tnet_stun_attr_vdata_ctor,
+ tnet_stun_attr_vdata_dtor,
+ _tnet_stun_attr_cmp,
+};
+const tsk_object_def_t *tnet_stun_attr_vdata_def_t = &tnet_stun_attr_vdata_def_s;
+
+
+// ============== ADDRESS ================ //
+int tnet_stun_attr_address_create(tnet_stun_attr_type_t e_type, tnet_stun_address_family_t e_family, uint16_t u_port, const tnet_stun_addr_t* pc_addr, tnet_stun_attr_address_t** pp_attr)
+{
+ int ret = -1;
+ extern const tsk_object_def_t *tnet_stun_attr_address_def_t;
+ tnet_stun_attr_address_t* p_attr = tsk_null;
+ uint16_t u_length = (e_family == tnet_stun_address_family_ipv6) ? 16 : 4;
+ if (!pp_attr) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!(p_attr = tsk_object_new(tnet_stun_attr_address_def_t))) {
+ ret = -2;
+ goto bail;
+ }
+ if ((ret = tnet_stun_attr_init(TNET_STUN_ATTR(p_attr), e_type, u_length))) {
+ goto bail;
+ }
+ p_attr->e_family = e_family;
+ p_attr->u_port = u_port;
+ if (pc_addr) {
+ memcpy(p_attr->address, *pc_addr, u_length);
+ }
+ *pp_attr = p_attr;
+
+bail:
+ if (ret) {
+ TSK_OBJECT_SAFE_FREE(p_attr);
+ }
+ return ret;
+}
+
+static tsk_object_t* tnet_stun_attr_address_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_stun_attr_address_t *p_addr = (tnet_stun_attr_address_t *)self;
+ if (p_addr) {
+ }
+ return self;
+}
+static tsk_object_t* tnet_stun_attr_address_dtor(tsk_object_t * self)
+{
+ tnet_stun_attr_address_t *p_addr = (tnet_stun_attr_address_t *)self;
+ if (p_addr) {
+#if PRINT_DESTROYED_MSG
+ TSK_DEBUG_INFO("*** STUN Attribute(ADDRESS) destroyed ***");
+#endif
+ }
+ return self;
+}
+static const tsk_object_def_t tnet_stun_attr_address_def_s = {
+ sizeof(tnet_stun_attr_address_t),
+ tnet_stun_attr_address_ctor,
+ tnet_stun_attr_address_dtor,
+ _tnet_stun_attr_cmp,
+};
+const tsk_object_def_t *tnet_stun_attr_address_def_t = &tnet_stun_attr_address_def_s;
+
+
+
+// ================ 15.6. ERROR-CODE ========== //
+int tnet_stun_attr_error_code_create(uint8_t u_class, uint8_t u_number, const void* pc_reason_phrase, uint16_t u_reason_phrase, struct tnet_stun_attr_error_code_s** pp_attr)
+{
+ int ret = -1;
+ extern const tsk_object_def_t *tnet_stun_attr_error_code_def_t;
+ tnet_stun_attr_error_code_t* p_attr = tsk_null;
+ uint16_t u_length = (uint16_t)(4 + tsk_strlen(pc_reason_phrase));
+ if (!pp_attr) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!(p_attr = tsk_object_new(tnet_stun_attr_error_code_def_t))) {
+ ret = -2;
+ goto bail;
+ }
+ if ((ret = tnet_stun_attr_init(TNET_STUN_ATTR(p_attr), tnet_stun_attr_type_error_code, u_length))) {
+ goto bail;
+ }
+ p_attr->u_class = u_class;
+ p_attr->u_number = u_number;
+ if (pc_reason_phrase && u_reason_phrase) {
+ if (!(p_attr->p_reason_phrase = tsk_strndup(pc_reason_phrase, u_reason_phrase))) {
+ ret = -3;
+ goto bail;
+ }
+ }
+ *pp_attr = p_attr;
+
+bail:
+ if (ret) {
+ TSK_OBJECT_SAFE_FREE(p_attr);
+ }
+ return ret;
+}
+
+static tsk_object_t* tnet_stun_attr_error_code_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_stun_attr_error_code_t *p_ec = (tnet_stun_attr_error_code_t *)self;
+ if (p_ec) {
+ }
+ return self;
+}
+static tsk_object_t* tnet_stun_attr_error_code_dtor(tsk_object_t * self)
+{
+ tnet_stun_attr_error_code_t *p_ec = (tnet_stun_attr_error_code_t *)self;
+ if (p_ec) {
+#if PRINT_DESTROYED_MSG
+ TSK_DEBUG_INFO("*** STUN Attribute(ERROR-CODE) destroyed ***");
+#endif
+ TSK_FREE(p_ec->p_reason_phrase);
+ }
+ return self;
+}
+static const tsk_object_def_t tnet_stun_attr_error_code_def_s = {
+ sizeof(tnet_stun_attr_error_code_t),
+ tnet_stun_attr_error_code_ctor,
+ tnet_stun_attr_error_code_dtor,
+ _tnet_stun_attr_cmp,
+};
+const tsk_object_def_t *tnet_stun_attr_error_code_def_t = &tnet_stun_attr_error_code_def_s;
diff --git a/tinyNET/src/stun/tnet_stun_attr.h b/tinyNET/src/stun/tnet_stun_attr.h
new file mode 100644
index 0000000..0052c66
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_attr.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_STUN_ATTR_H
+#define TNET_STUN_ATTR_H
+
+#include "tinynet_config.h"
+#include "stun/tnet_stun_types.h"
+
+#include "tsk_object.h"
+#include "tsk_list.h"
+
+TNET_BEGIN_DECLS
+
+// rfc5389 - 15. STUN Attributes
+typedef struct tnet_stun_attr_hdr_xs {
+ enum tnet_stun_attr_type_e e_type; // 16bits
+ uint16_t u_length; // 16bits prior to padding, measured in bytes (WITHOUT header)
+} tnet_stun_attr_hdr_xt;
+
+typedef struct tnet_stun_attr_s {
+ TSK_DECLARE_OBJECT;
+ struct tnet_stun_attr_s* pc_base;
+ struct tnet_stun_attr_hdr_xs hdr;
+} tnet_stun_attr_t;
+#define TNET_STUN_DECLARE_ATTR struct tnet_stun_attr_s __base__
+#define TNET_STUN_ATTR(p_self) ((struct tnet_stun_attr_s*)(p_self))
+typedef tsk_list_t tnet_stun_attrs_L_t;
+int tnet_stun_attr_init(struct tnet_stun_attr_s* p_self, enum tnet_stun_attr_type_e e_type, uint16_t u_length);
+TINYNET_API int tnet_stun_attr_get_size_in_octetunits_without_padding(const struct tnet_stun_attr_s* pc_self, tsk_size_t* p_size);
+TINYNET_API int tnet_stun_attr_get_size_in_octetunits_with_padding(const struct tnet_stun_attr_s* pc_self, tsk_size_t* p_size);
+TINYNET_API int tnet_stun_attr_write_without_padding(const tnet_stun_transac_id_t* pc_transac_id, const struct tnet_stun_attr_s* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written);
+TINYNET_API int tnet_stun_attr_write_with_padding(const tnet_stun_transac_id_t* pc_transac_id, const struct tnet_stun_attr_s* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written);
+TINYNET_API int tnet_stun_attr_read(const tnet_stun_transac_id_t* pc_transac_id, const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_consumed_octets, struct tnet_stun_attr_s** pp_attr);
+
+// ============== VDATA (USERNAME, MESSAGE-INTEGRITY, REALM, NONCE, ...) ================ //
+typedef struct tnet_stun_attr_vdata_s {
+ TNET_STUN_DECLARE_ATTR;
+ uint8_t *p_data_ptr;
+ uint16_t u_data_size;
+} tnet_stun_attr_vdata_t;
+int tnet_stun_attr_vdata_create(enum tnet_stun_attr_type_e e_type, const uint8_t* pc_data_ptr, uint16_t u_data_size, struct tnet_stun_attr_vdata_s** pp_attr);
+int tnet_stun_attr_vdata_update(struct tnet_stun_attr_vdata_s* p_self, const uint8_t* pc_data_ptr, uint16_t u_data_size);
+
+// ============== ADDRESS ================ //
+typedef struct tnet_stun_attr_address_s {
+ TNET_STUN_DECLARE_ATTR;
+ enum tnet_stun_address_family_e e_family; // 8bits
+ uint16_t u_port; // 16bits
+ tnet_stun_addr_t address; // always in network byte order. Use tnet_stun_utils_inet_pton()
+} tnet_stun_attr_address_t;
+
+int tnet_stun_attr_address_create(enum tnet_stun_attr_type_e e_type, enum tnet_stun_address_family_e e_family, uint16_t u_port, const tnet_stun_addr_t* pc_addr, struct tnet_stun_attr_address_s** pp_attr);
+
+// ================ 15.6. ERROR-CODE ========== //
+typedef struct tnet_stun_attr_error_code_s {
+ TNET_STUN_DECLARE_ATTR;
+ uint8_t u_class; // 3bits
+ uint8_t u_number; // 8bits
+ char* p_reason_phrase;
+} tnet_stun_attr_error_code_t;
+int tnet_stun_attr_error_code_create(uint8_t u_class, uint8_t u_number, const void* pc_reason_phrase, uint16_t u_reason_phrase, struct tnet_stun_attr_error_code_s** pp_attr);
+
+TNET_END_DECLS
+
+#endif /* TNET_STUN_ATTR_H */
diff --git a/tinyNET/src/stun/tnet_stun_attribute.c b/tinyNET/src/stun/tnet_stun_attribute.c
new file mode 100644
index 0000000..b8efdcc
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_attribute.c
@@ -0,0 +1,1176 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_stun_attribute.c
+// * @brief STUN2(RFC 5389) attribute parser.
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#include "tnet_stun_attribute.h"
+//
+//#include "tnet_stun.h"
+//
+//#include "../tnet_types.h"
+//#include "../tnet_endianness.h"
+//
+//#include "../turn/tnet_turn_attribute.h"
+//#include "stun/tnet_stun_types.h"
+//
+//#include "tsk_memory.h"
+//#include "tsk_string.h"
+//#include "tsk_debug.h"
+//
+//#include <string.h>
+//
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15. STUN Attributes
+//* Creates new @ref tnet_stun_attribute_def_t object.
+//*/
+//tnet_stun_attr_t* tnet_stun_attribute_create()
+//{
+// return tsk_object_new(tnet_stun_attribute_def_t);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.1. MAPPED-ADDRESS.
+//* Creates new @ref tnet_stun_attribute_mapped_addr_t object.
+//*/
+//tnet_stun_attribute_mapped_addr_t* tnet_stun_attribute_mapped_address_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_stun_attribute_mapped_addr_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS.
+//* Creates new @ref tnet_stun_attribute_xmapped_addr_t object.
+//*/
+//tnet_stun_attribute_xmapped_addr_t* tnet_stun_attribute_xmapped_address_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_stun_attribute_xmapped_addr_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.3. USERNAME.
+//* Creates new @ref tnet_stun_attribute_username_t object.
+//*/
+//tnet_stun_attribute_username_t* tnet_stun_attribute_username_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_stun_attribute_username_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.4. MESSAGE-INTEGRITY.
+//* Creates new @ref tnet_stun_attribute_integrity_t object.
+//*/
+//tnet_stun_attribute_integrity_t* tnet_stun_attribute_integrity_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_stun_attribute_integrity_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.5. FINGERPRINT.
+//* Creates new @ref tnet_stun_attribute_fingerprint_t object.
+//*/
+//tnet_stun_attribute_fingerprint_t* tnet_stun_attribute_fingerprint_create(uint32_t fingerprint)
+//{
+// return tsk_object_new(tnet_stun_attribute_fingerprint_def_t, fingerprint);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.6. ERROR-CODE
+//* Creates new @ref tnet_stun_attribute_errorcode_t object.
+//*/
+//tnet_stun_attribute_errorcode_t* tnet_stun_attribute_errorcode_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_stun_attribute_errorcode_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.7. REALM.
+//* Creates new @ref tnet_stun_attribute_realm_t object.
+//*/
+//tnet_stun_attribute_realm_t* tnet_stun_attribute_realm_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_stun_attribute_realm_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.8. NONCE.
+//* Creates new @ref tnet_stun_attribute_nonce_t object.
+//*/
+//tnet_stun_attribute_nonce_t* tnet_stun_attribute_nonce_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_stun_attribute_nonce_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.9. UNKNOWN-ATTRIBUTES.
+//* Creates new @ref tnet_stun_attribute_unknowns_t object.
+//*/
+//tnet_stun_attribute_unknowns_t* tnet_stun_attribute_unknowns_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_stun_attribute_unknowns_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.10. SOFTWARE.
+//* Creates new @ref tnet_stun_attribute_software_t object.
+//*/
+//tnet_stun_attribute_software_t* tnet_stun_attribute_software_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_stun_attribute_software_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.11. ALTERNATE-SERVER.
+//* Creates new @ref tnet_stun_attribute_altserver_t object.
+//*/
+//tnet_stun_attribute_altserver_t* tnet_stun_attribute_altserver_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_stun_attribute_altserver_def_t, payload, payload_size);
+//}
+//
+//
+//
+///**@ingroup tnet_stun_group
+//* RFC 5245 - 19.1. PRIORITY */
+//tnet_stun_attribute_ice_priority_t* tnet_stun_attribute_ice_priority_create(uint32_t value)
+//{
+// return tsk_object_new(tnet_stun_attribute_ice_priority_def_t, value);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5245 - 19.1. USE_CANDIDATE */
+//tnet_stun_attribute_ice_use_candidate_t* tnet_stun_attribute_ice_use_candidate_create()
+//{
+// return tsk_object_new(tnet_stun_attribute_ice_use_candidate_def_t);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5245 - 19.1. ICE_CONTROLLED */
+//tnet_stun_attribute_ice_controlled_t* tnet_stun_attribute_ice_controlled_create(uint64_t value)
+//{
+// return tsk_object_new(tnet_stun_attribute_ice_controlled_def_t, value);
+//}
+//
+///**@ingroup tnet_stun_group
+//* RFC 5245 - 19.1. ICE_CONTROLLING */
+//tnet_stun_attribute_ice_controlling_t* tnet_stun_attribute_ice_controlling_create(uint64_t value)
+//{
+// return tsk_object_new(tnet_stun_attribute_ice_controlling_def_t, value);
+//}
+//
+//
+//
+//
+///**@ingroup tnet_stun_group
+//* Creates @ref tnet_stun_attr_t from raw buffer.
+//* @param data Raw buffer from which to create the STUN attribute.*
+//* @param size The size of the eaw buffer.
+//* @retval @ref tnet_stun_attr_t object if succeed and NULL other wise.
+//*/
+//tnet_stun_attr_t* tnet_stun_attribute_deserialize(const void* data, tsk_size_t size)
+//{
+// tnet_stun_attr_t *attribute = 0;
+// const uint8_t* dataPtr = data;
+//
+// tnet_stun_attr_type_t type = (tnet_stun_attr_type_t)tnet_ntohs_2(dataPtr);
+// uint16_t length = tnet_ntohs_2(&dataPtr[2]);
+//
+// /* Check validity */
+// if(!data || size<=4/* Type(2-bytes) plus Length (2-bytes) */) {
+// return 0;
+// }
+//
+// dataPtr += (2 /* Type */+ 2/* Length */);
+//
+// /* Attribute Value
+// */
+//
+// switch(type) {
+// /* RFC 5389 - 15.1. MAPPED-ADDRESS */
+// case stun_mapped_address: {
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_mapped_address_create(dataPtr, length);
+// break;
+// }
+//
+// /* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS*/
+// case stun_xor_mapped_address: {
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_xmapped_address_create(dataPtr, length);
+// break;
+// }
+//
+// /* RFC 5389 - 15.3. USERNAME*/
+// case stun_username: {
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_username_create(dataPtr, length);
+// break;
+// }
+//
+//
+// /* RFC 5389 - MESSAGE-INTEGRITY*/
+// case stun_message_integrity: {
+// if(length == TSK_SHA1_DIGEST_SIZE) {
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_integrity_create(dataPtr, length);
+// }
+// break;
+// }
+//
+// /* RFC 5389 - 15.5. FINGERPRINT*/
+// case stun_fingerprint: {
+// uint32_t fingerprint = tnet_htonl_2(dataPtr);
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_fingerprint_create(fingerprint);
+// break;
+// }
+//
+// /* RFC 5389 - 15.6. ERROR-CODE*/
+// case stun_error_code: {
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_errorcode_create(dataPtr, length);
+// break;
+// }
+//
+// /* RFC 5389 - 15.7. REALM*/
+// case stun_realm: {
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_realm_create(dataPtr, length);
+// break;
+// }
+//
+// /* RFC 5389 - 15.8. NONCE*/
+// case stun_nonce: {
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_nonce_create(dataPtr, length);
+// break;
+// }
+//
+// /* RFC 5389 - 15.9. UNKNOWN-ATTRIBUTES*/
+// case stun_unknown_attributes: {
+// TSK_DEBUG_ERROR("DESERIALIZE:UNKNOWN-ATTRIBUTES ==> NOT IMPLEMENTED");
+// attribute = tnet_stun_attribute_create();
+// break;
+// }
+//
+// /* RFC 5389 - 15.10. SOFTWARE */
+// case stun_software: {
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_software_create(dataPtr, length);
+// break;
+// }
+//
+// /* RFC 5389 - 15.11. ALTERNATE-SERVER */
+// case stun_alternate_server: {
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_altserver_create(dataPtr, length);
+// break;
+// }
+//
+// /* draft-ietf-behave-turn-16 subclause 14 */
+// case stun_channel_number:
+// case stun_lifetime:
+// case stun_reserved2:
+// case stun_xor_peer_address:
+// case stun_data:
+// case stun_xor_relayed_address:
+// case stun_even_port:
+// case stun_requested_transport:
+// case stun_dont_fragment:
+// case stun_reserved3:
+// case stun_reservation_token: {
+// //attribute = tnet_turn_attribute_deserialize(type, length, dataPtr, length);
+// attribute = 0;
+// break;
+// }
+//
+// /* RFC 5245 - 19.1. PRIORITY */
+// case stun_ice_priority: {
+// if(length >= 4) {
+// uint32_t value = dataPtr[0] << 24 | dataPtr[1] << 16 | dataPtr[2] << 8 | dataPtr[3];
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_ice_priority_create(value);
+// }
+// break;
+// }
+// /* RFC 5245 - 19.1. USE_CANDIDATE */
+// case stun_ice_use_candidate: {
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_ice_use_candidate_create();
+// break;
+// }
+// /* RFC 5245 - 19.1. ICE_CONTROLLED*/
+// case stun_ice_controlled: {
+// if(length >= 8) {
+// uint64_t value = ((((uint64_t)dataPtr[0]) << 56) | (((uint64_t)dataPtr[1]) << 48) | (((uint64_t)dataPtr[2]) << 40) | (((uint64_t)dataPtr[3]) << 32) | (((uint64_t)dataPtr[4]) << 24) | (((uint64_t)dataPtr[5]) << 16) | ((uint64_t)dataPtr[6]) << 8 | ((uint64_t)dataPtr[7]));
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_ice_controlled_create(value);
+// }
+// break;
+// }
+// /* RFC 5245 - 19.1. ICE_CONTROLLING*/
+// case stun_ice_controlling: {
+// if(length >= 8) {
+// uint64_t value = ((((uint64_t)dataPtr[0]) << 56) | (((uint64_t)dataPtr[1]) << 48) | (((uint64_t)dataPtr[2]) << 40) | (((uint64_t)dataPtr[3]) << 32) | (((uint64_t)dataPtr[4]) << 24) | (((uint64_t)dataPtr[5]) << 16) | ((uint64_t)dataPtr[6]) << 8 | ((uint64_t)dataPtr[7]));
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_ice_controlling_create(value);
+// }
+// break;
+// }
+//
+//
+// default:
+// //TSK_DEBUG_WARN("==> NOT IMPLEMENTED");
+// break;
+// }
+//
+// if(!attribute) {
+// /* Create default */
+// attribute = tnet_stun_attribute_create();
+// }
+//
+// /* Set common values (Do I need this ==> already set by the constructor). */
+// attribute->type = type;
+// attribute->length = length;
+//
+// return attribute;
+//}
+//
+///**@ingroup tnet_stun_group
+//* Serializes a @ref tnet_stun_attr_t objet in binary format.
+//* @param attribute The STUN attribute to serialize.
+//* @param output The output binary buffer.
+//* @retval Zero if succeed and non-zero error code otherwise.
+//*/
+//int tnet_stun_attribute_serialize(const tnet_stun_attr_t* attribute, tsk_buffer_t *output)
+//{
+// if(!attribute || !output) {
+// return -1;
+// }
+//
+// /* Attribute Type
+// */
+// {
+// uint16_t type = tnet_htons(attribute->type);
+// tsk_buffer_append(output, &(type), 2);
+// }
+//
+// /* Attribute Length
+// */
+// {
+// uint16_t length = tnet_htons(attribute->length);
+// tsk_buffer_append(output, &(length), 2);
+// }
+//
+// /* Attribute Value */
+// // NEED to be refactorized
+//
+// switch(attribute->type) {
+// /* RFC 5389 - 15.1. MAPPED-ADDRESS */
+// case stun_mapped_address: {
+// uint32_t u32 = 0;
+// tnet_stun_attribute_mapped_addr_t* ma = (tnet_stun_attribute_mapped_addr_t*)attribute;
+// tsk_size_t addr_size, i;
+// uint32_t addr[4];
+//
+// u32 |= (ma->family << 16);
+// u32 |= (ma->port);
+// u32 = tnet_htonl(u32);
+// tsk_buffer_append(output, &u32, 4);
+//
+// addr_size = (ma->family == stun_ipv6 ? 16 : 4);
+// for(i = 0; i < addr_size; i += 4) {
+// addr[i >> 2] = tnet_htonl_2(&ma->address[i]);
+// }
+// tsk_buffer_append(output, addr, addr_size);
+//
+// return 0;
+// }
+//
+// /* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS*/
+// case stun_xor_mapped_address: {
+// uint32_t u32 = 0;
+// tnet_stun_attribute_xmapped_addr_t* xma = (tnet_stun_attribute_xmapped_addr_t*)attribute;
+// tsk_size_t addr_size, i;
+// uint32_t addr[4];
+//
+// u32 |= (xma->family << 16);
+// u32 |= (xma->xport);
+// u32 = tnet_htonl(u32);
+// tsk_buffer_append(output, &u32, 4);
+//
+// addr_size = (xma->family == stun_ipv6 ? 16 : 4);
+// for(i = 0; i < addr_size; i += 4) {
+// addr[i >> 2] = tnet_htonl_2(&xma->xaddress[i]);
+// }
+// tsk_buffer_append(output, addr, addr_size);
+// return 0;
+// }
+//
+// /* RFC 5389 - 15.3. USERNAME*/
+// case stun_username: {
+// tnet_stun_attribute_username_t *username = (tnet_stun_attribute_username_t*)attribute;
+// tsk_buffer_append(output, username->value, tsk_strlen(username->value));
+// return 0;
+// }
+//
+//
+// /* RFC 5389 - MESSAGE-INTEGRITY*/
+// case stun_message_integrity: {
+// tnet_stun_attribute_integrity_t *integrity = (tnet_stun_attribute_integrity_t*)attribute;
+// tsk_buffer_append(output, integrity->sha1digest, TSK_SHA1_DIGEST_SIZE);
+// return 0;
+// }
+//
+// /* RFC 5389 - 15.5. FINGERPRINT*/
+// case stun_fingerprint: {
+// uint32_t fingerprint = /*tnet_htonl*/(((tnet_stun_attribute_fingerprint_t*)attribute)->value);
+// tsk_buffer_append(output, &fingerprint, 4);
+// return 0;
+// }
+//
+// /* RFC 5389 - 15.6. ERROR-CODE*/
+// case stun_error_code: {
+// uint32_t u32 = 0;
+// tnet_stun_attribute_errorcode_t *errorcode = (tnet_stun_attribute_errorcode_t*)attribute;
+// u32 |= (errorcode->_class & 0x07) << 8;
+// u32 |= errorcode->number;
+// u32 = tnet_htonl(u32);
+// tsk_buffer_append(output, &u32, 4);
+// tsk_buffer_append(output, errorcode->reason_phrase, tsk_strlen(errorcode->reason_phrase));
+// return 0;
+// }
+//
+// /* RFC 5389 - 15.7. REALM*/
+// case stun_realm: {
+// tnet_stun_attribute_realm_t *realm = (tnet_stun_attribute_realm_t*)attribute;
+// tsk_buffer_append(output, realm->value, tsk_strlen(realm->value));
+// return 0;
+// }
+//
+// /* RFC 5389 - 15.8. NONCE*/
+// case stun_nonce: {
+// tnet_stun_attribute_nonce_t *nonce = (tnet_stun_attribute_nonce_t*)attribute;
+// tsk_buffer_append(output, nonce->value, tsk_strlen(nonce->value));
+// return 0;
+// }
+//
+// /* RFC 5389 - 15.9. UNKNOWN-ATTRIBUTES*/
+// case stun_unknown_attributes: {
+// TSK_DEBUG_ERROR("NOT IMPLEMENTED");
+// return -3;
+// }
+//
+// /* RFC 5389 - 15.10. SOFTWARE */
+// case stun_software: {
+// tnet_stun_attribute_software_t *software = (tnet_stun_attribute_software_t*)attribute;
+// tsk_buffer_append(output, software->value, tsk_strlen(software->value));
+// return 0;
+// }
+//
+// /* RFC 5389 - 15.11. ALTERNATE-SERVER */
+// case stun_alternate_server: {
+// TSK_DEBUG_ERROR("NOT IMPLEMENTED");
+// return -3;
+// }
+// /* draft-ietf-behave-turn-16 - */
+// case stun_channel_number:
+// case stun_lifetime:
+// case stun_reserved2:
+// case stun_xor_peer_address:
+// case stun_data:
+// case stun_xor_relayed_address:
+// case stun_even_port:
+// case stun_requested_transport:
+// case stun_dont_fragment:
+// case stun_reserved3:
+// case stun_reservation_token: {
+// return -1;//tnet_turn_attribute_serialize(attribute, output);
+// }
+//
+//
+// /* RFC 5245 - 19.1. PRIORITY */
+// case stun_ice_priority: {
+// uint32_t value = tnet_htonl(((tnet_stun_attribute_ice_priority_t*)attribute)->value);
+// tsk_buffer_append(output, &value, 4);
+// return 0;
+// }
+// /* RFC 5245 - 19.1. USE_CANDIDATE */
+// case stun_ice_use_candidate: {
+// // no body
+// return 0;
+// }
+// /* RFC 5245 - 19.1. ICE_CONTROLLED */
+// case stun_ice_controlled: {
+// uint64_t value = ((tnet_stun_attribute_ice_controlled_t*)attribute)->value;
+// value = ((((uint64_t)tnet_htonl(value >> 32)) << 32) | ((uint64_t)tnet_htonl(value & 0xFFFFFFFF)));
+// tsk_buffer_append(output, &value, 8);
+// return 0;
+// }
+// /* RFC 5245 - 19.1. ICE_CONTROLLING */
+// case stun_ice_controlling: {
+// uint64_t value = ((tnet_stun_attribute_ice_controlling_t*)attribute)->value;
+// value = ((((uint64_t)tnet_htonl(value >> 32)) << 32) | ((uint64_t)tnet_htonl(value & 0xFFFFFFFF)));
+// tsk_buffer_append(output, &value, 8);
+// return 0;
+// }
+//
+// default:
+// return -2;
+// }
+//}
+//
+///**@ingroup tnet_stun_group
+//* Pads a STUN attribute to align it on 4 octets.
+//* @param attribute The STUN attribute to pad.
+//* @param output The output buffer into which to put zeros.
+//*/
+//void tnet_stun_attribute_pad(const tnet_stun_attr_t* attribute, tsk_buffer_t *output)
+//{
+// if(attribute->length & 0x03) {
+// static uint32_t zeros = 0x00000000;
+// tsk_buffer_append(output, &zeros, 4-(attribute->length & 0x03));
+// }
+//}
+//
+//
+//
+//
+////=================================================================================================
+//// [[RFC 5389 - 15. STUN Attributes]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attr_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attr_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_def_s = {
+// sizeof(tnet_stun_attr_t),
+// tnet_stun_attribute_ctor,
+// tnet_stun_attribute_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_def_t = &tnet_stun_attribute_def_s;
+//
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.1. MAPPED-ADDRESS]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_mapped_addr_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_mapped_addr_t *attribute = self;
+// if(attribute) {
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// if(payload && payload_size) {
+// const uint8_t *payloadPtr = (const uint8_t*)payload;
+// payloadPtr += 1; /* Ignore first 8bits */
+//
+// attribute->family = (tnet_stun_addr_family_t) (*(payloadPtr++));
+// attribute->port = tnet_ntohs_2(payloadPtr);
+// payloadPtr+=2;
+//
+// { /*=== Compute IP address */
+// tsk_size_t addr_size = (attribute->family == stun_ipv6) ? 16 : (attribute->family == stun_ipv4 ? 4 : 0);
+// if(addr_size) {
+// tsk_size_t i;
+//
+// for(i=0; i<addr_size; i+=4) {
+// // ntohl() not needed : byte per byte to avoid endianness problem
+// attribute->address[i] = payloadPtr[0],
+// attribute->address[i+1] = payloadPtr[1],
+// attribute->address[i+2] = payloadPtr[2],
+// attribute->address[i+3] = payloadPtr[3];
+// payloadPtr+=4;
+// }
+// }
+// else {
+// TSK_DEBUG_ERROR("UNKNOWN FAMILY [%u].", attribute->family);
+// }
+// }
+// }
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_mapped_address;
+// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_mapped_addr_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_mapped_addr_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_mapped_addr_def_s = {
+// sizeof(tnet_stun_attribute_mapped_addr_t),
+// tnet_stun_attribute_mapped_addr_ctor,
+// tnet_stun_attribute_mapped_addr_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_mapped_addr_def_t = &tnet_stun_attribute_mapped_addr_def_s;
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.2. XOR-MAPPED-ADDRESS]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_xmapped_addr_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_xmapped_addr_t *attribute = self;
+// if(attribute) {
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// if(payload && payload_size) {
+// const uint8_t *payloadPtr = (const uint8_t*)payload;
+// payloadPtr += 1; /* Ignore first 8bits */
+//
+// attribute->family = (tnet_stun_addr_family_t)(*(payloadPtr++));
+//
+// /* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS
+// X-Port is computed by taking the mapped port in host byte order,
+// XOR'ing it with the most significant 16 bits of the magic cookie, and
+// then the converting the result to network byte order.
+// */
+// attribute->xport = tnet_ntohs_2(payloadPtr);
+// attribute->xport ^= 0x2112;
+// payloadPtr+=2;
+//
+//
+// { /*=== Compute IP address */
+//
+// /* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS
+// If the IP address family is IPv4, X-Address is computed by taking the mapped IP
+// address in host byte order, XOR'ing it with the magic cookie, and
+// converting the result to network byte order.
+// */
+// tsk_size_t addr_size = (attribute->family == stun_ipv6) ? 16 : (attribute->family == stun_ipv4 ? 4 : 0);
+// if(addr_size) {
+// tsk_size_t i;
+// uint32_t addr;
+//
+// for(i=0; i<addr_size; i+=4) {
+// addr = tnet_ntohl(tnet_ntohl_2(payloadPtr) ^ kStunMagicCookieLong);
+// memcpy(&attribute->xaddress[i], &addr, 4);
+// payloadPtr+=4;
+// }
+// }
+// else {
+// TSK_DEBUG_ERROR("UNKNOWN FAMILY [%u].", attribute->family);
+// }
+// }
+// }
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_xor_mapped_address;
+// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+//
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_xmapped_addr_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_xmapped_addr_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_xmapped_addr_def_s = {
+// sizeof(tnet_stun_attribute_xmapped_addr_t),
+// tnet_stun_attribute_xmapped_addr_ctor,
+// tnet_stun_attribute_xmapped_addr_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_xmapped_addr_def_t = &tnet_stun_attribute_xmapped_addr_def_s;
+//
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.3. USERNAME]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_username_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_username_t *attribute = self;
+// if(attribute) {
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// attribute->value = tsk_strndup(payload, payload_size);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_username;
+// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_username_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_username_t *attribute = self;
+// if(attribute) {
+// TSK_FREE(attribute->value);
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_username_def_s = {
+// sizeof(tnet_stun_attribute_username_t),
+// tnet_stun_attribute_username_ctor,
+// tnet_stun_attribute_username_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_username_def_t = &tnet_stun_attribute_username_def_s;
+//
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.4. MESSAGE-INTEGRITY]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_integrity_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_integrity_t *attribute = self;
+// if(attribute) {
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// if(payload_size == TSK_SHA1_DIGEST_SIZE) {
+// memcpy(attribute->sha1digest, payload, TSK_SHA1_DIGEST_SIZE);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_message_integrity;
+// TNET_STUN_ATTRIBUTE(attribute)->length = TSK_SHA1_DIGEST_SIZE;
+// }
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_integrity_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_integrity_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_integrity_def_s = {
+// sizeof(tnet_stun_attribute_integrity_t),
+// tnet_stun_attribute_integrity_ctor,
+// tnet_stun_attribute_integrity_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_integrity_def_t = &tnet_stun_attribute_integrity_def_s;
+//
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.5. FINGERPRINT]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_fingerprint_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_fingerprint_t *attribute = self;
+// if(attribute) {
+// attribute->value = va_arg(*app, uint32_t);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_fingerprint;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 4;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_fingerprint_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_fingerprint_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_fingerprint_def_s = {
+// sizeof(tnet_stun_attribute_fingerprint_t),
+// tnet_stun_attribute_fingerprint_ctor,
+// tnet_stun_attribute_fingerprint_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_fingerprint_def_t = &tnet_stun_attribute_fingerprint_def_s;
+//
+//
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.6. ERROR-CODE]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_errorcode_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_errorcode_t *attribute = self;
+// if(attribute) {
+// const uint8_t *payload = (const uint8_t*)va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// if(payload_size >4) {
+// uint32_t code = tnet_htonl_2(payload);
+// payload += 4;
+//
+// attribute->_class = code >>8;
+// attribute->number = (code & 0xFF);
+// attribute->reason_phrase = tsk_strndup((const char*)payload, (payload_size-4));
+// }
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_error_code;
+// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_errorcode_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_errorcode_t *attribute = self;
+// if(attribute) {
+// TSK_FREE(attribute->reason_phrase);
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_errorcode_def_s = {
+// sizeof(tnet_stun_attribute_errorcode_t),
+// tnet_stun_attribute_errorcode_ctor,
+// tnet_stun_attribute_errorcode_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_errorcode_def_t = &tnet_stun_attribute_errorcode_def_s;
+//
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.7. REALM]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_realm_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_realm_t *attribute = self;
+// if(attribute) {
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// attribute->value = tsk_strndup(payload, payload_size);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_realm;
+// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_realm_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_realm_t *attribute = self;
+// if(attribute) {
+// TSK_FREE(attribute->value);
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_realm_def_s = {
+// sizeof(tnet_stun_attribute_realm_t),
+// tnet_stun_attribute_realm_ctor,
+// tnet_stun_attribute_realm_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_realm_def_t = &tnet_stun_attribute_realm_def_s;
+//
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.8. NONCE]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_nonce_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_nonce_t *attribute = self;
+// if(attribute) {
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// attribute->value = tsk_strndup(payload, payload_size);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_nonce;
+// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_nonce_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_nonce_t *attribute = self;
+// if(attribute) {
+// TSK_FREE(attribute->value);
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_nonce_def_s = {
+// sizeof(tnet_stun_attribute_nonce_t),
+// tnet_stun_attribute_nonce_ctor,
+// tnet_stun_attribute_nonce_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_nonce_def_t = &tnet_stun_attribute_nonce_def_s;
+//
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.9. UNKNOWN-ATTRIBUTES]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_unknowns_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_unknowns_t *attribute = self;
+// if(attribute) {
+// //--const void *payload = va_arg(*app, const void*);
+// //--tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_unknown_attributes;
+// attribute->value = tsk_buffer_create_null();
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_unknowns_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_unknowns_t *attribute = self;
+// if(attribute) {
+// TSK_OBJECT_SAFE_FREE(attribute->value);
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_unknowns_def_s = {
+// sizeof(tnet_stun_attribute_unknowns_t),
+// tnet_stun_attribute_unknowns_ctor,
+// tnet_stun_attribute_unknowns_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_unknowns_def_t = &tnet_stun_attribute_unknowns_def_s;
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.10. SOFTWARE]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_software_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_software_t *attribute = self;
+// if(attribute) {
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_software;
+//
+// attribute->value = tsk_strndup(payload, payload_size);
+// TNET_STUN_ATTRIBUTE(attribute)->length = tsk_strlen(attribute->value);
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_software_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_software_t *attribute = self;
+// if(attribute) {
+// TSK_FREE(attribute->value);
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_software_def_s = {
+// sizeof(tnet_stun_attribute_software_t),
+// tnet_stun_attribute_software_ctor,
+// tnet_stun_attribute_software_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_software_def_t = &tnet_stun_attribute_software_def_s;
+//
+////=================================================================================================
+//// [[RFC 5389 - 15.11. ALTERNATE-SERVER]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_altserver_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_altserver_t *attribute = self;
+// if(attribute) {
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// const uint8_t *payloadPtr = (const uint8_t*)payload;
+// payloadPtr += 1; /* Ignore first 8bits */
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_alternate_server;
+// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+//
+// attribute->family = (tnet_stun_addr_family_t) (*(payloadPtr++));
+// attribute->port = tnet_ntohs_2(payloadPtr);
+// payloadPtr+=2;
+//
+// if(attribute->family == stun_ipv4) {
+// uint32_t addr = tnet_htonl_2(payloadPtr);
+// memcpy(attribute->server, &addr, 4);
+// payloadPtr+=4;
+// }
+// else if(attribute->family == stun_ipv6) {
+// TSK_DEBUG_ERROR("IPv6 not supported yet.");
+// }
+// else {
+// TSK_DEBUG_ERROR("UNKNOWN FAMILY.");
+// }
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_altserver_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_altserver_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_altserver_def_s = {
+// sizeof(tnet_stun_attribute_altserver_t),
+// tnet_stun_attribute_altserver_ctor,
+// tnet_stun_attribute_altserver_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_altserver_def_t = &tnet_stun_attribute_altserver_def_s;
+//
+//
+////=================================================================================================
+//// [[RFC 5245 - 19.1. PRIORITY]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_ice_priority_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_ice_priority_t *attribute = self;
+// if(attribute) {
+// attribute->value = va_arg(*app, uint32_t);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_ice_priority;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 4;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_ice_priority_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_ice_priority_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_ice_priority_def_s = {
+// sizeof(tnet_stun_attribute_ice_priority_t),
+// tnet_stun_attribute_ice_priority_ctor,
+// tnet_stun_attribute_ice_priority_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_ice_priority_def_t = &tnet_stun_attribute_ice_priority_def_s;
+//
+//
+////=================================================================================================
+//// [[RFC 5245 - 19.1. USE-CANDIDATE]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_ice_use_candidate_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_ice_use_candidate_t *attribute = self;
+// if(attribute) {
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_ice_use_candidate;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 0;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_ice_use_candidate_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_ice_use_candidate_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_ice_use_candidate_def_s = {
+// sizeof(tnet_stun_attribute_ice_use_candidate_t),
+// tnet_stun_attribute_ice_use_candidate_ctor,
+// tnet_stun_attribute_ice_use_candidate_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_ice_use_candidate_def_t = &tnet_stun_attribute_ice_use_candidate_def_s;
+//
+//
+////=================================================================================================
+//// [[RFC 5245 - 19.1. ICE-CONTROLLED]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_ice_controlled_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_ice_controlled_t *attribute = self;
+// if(attribute) {
+// attribute->value = va_arg(*app, uint64_t);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_ice_controlled;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 8;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_ice_controlled_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_ice_controlled_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_ice_controlled_def_s = {
+// sizeof(tnet_stun_attribute_ice_controlled_t),
+// tnet_stun_attribute_ice_controlled_ctor,
+// tnet_stun_attribute_ice_controlled_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_ice_controlled_def_t = &tnet_stun_attribute_ice_controlled_def_s;
+//
+//
+//
+////=================================================================================================
+//// [[RFC 5245 - 19.1. ICE-CONTROLLING]] object definition
+////
+//static tsk_object_t* tnet_stun_attribute_ice_controlling_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_attribute_ice_controlling_t *attribute = self;
+// if(attribute) {
+// attribute->value = va_arg(*app, uint64_t);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_ice_controlling;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 8;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_attribute_ice_controlling_dtor(tsk_object_t * self)
+//{
+// tnet_stun_attribute_ice_controlling_t *attribute = self;
+// if(attribute) {
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_attribute_ice_controlling_def_s = {
+// sizeof(tnet_stun_attribute_ice_controlling_t),
+// tnet_stun_attribute_ice_controlling_ctor,
+// tnet_stun_attribute_ice_controlling_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_attribute_ice_controlling_def_t = &tnet_stun_attribute_ice_controlling_def_s;
diff --git a/tinyNET/src/stun/tnet_stun_attribute.h b/tinyNET/src/stun/tnet_stun_attribute.h
new file mode 100644
index 0000000..d9e0de7
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_attribute.h
@@ -0,0 +1,356 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_stun_attribute.h
+// * @brief STUN2(RFC 5389) attribute parser.
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#ifndef TNET_STUN_ATTRIBUTE_H
+//#define TNET_STUN_ATTRIBUTE_H
+//
+//#include "tinynet_config.h"
+//
+//#include "tnet_types.h"
+//
+//#include "tsk_object.h"
+//#include "tsk_buffer.h"
+//#include "tsk_sha1.h"
+//
+///**@ingroup tnet_stun_group
+//* @def TNET_STUN_ATTRIBUTE
+//* Converts (cast) any STUN attribute to @ref tnet_stun_attr_t pointer.
+//* @param self The attribute to convert (cast).
+//* @retval A pointer to @ref tnet_stun_attr_t object.
+//*/
+//TNET_BEGIN_DECLS
+//
+//#define TNET_STUN_ATTRIBUTE(self) ((tnet_stun_attr_t*)(self))
+//
+///**@ingroup tnet_stun_group
+// * STUN IP family as per RFC 5389 subclause 15.1.
+//**/
+//typedef enum tnet_stun_addr_family_e {
+// stun_ipv4 = 0x01,
+// stun_ipv6 = 0x02
+//}
+//tnet_stun_addr_family_t;
+//
+///**@ingroup tnet_stun_group
+// * STUN attribute types as per RFC 5389 subclause 18.2.
+//**/
+//typedef enum tnet_stun_attr_type_e {
+// /* === RFC 5389 - Comprehension-required range (0x0000-0x7FFF) */
+// stun_reserved = 0x0000, /**< (Reserved) */
+// stun_mapped_address = 0x0001, /**< http://tools.ietf.org/html/rfc5389#page-32 */
+// stun_response_address = 0x0002, /**< (Reserved; was RESPONSE-ADDRESS) */
+// stun_change_address = 0x0003, /**< (Reserved; was CHANGE-ADDRESS) */
+// stun_source_address = 0x0004, /**< (Reserved; was SOURCE-ADDRESS) */
+// stun_changed_address = 0x0005, /**< (Reserved; was CHANGED-ADDRESS) */
+// stun_username = 0x0006, /**< http://tools.ietf.org/html/rfc5389#page-34 */
+// stun_password = 0x0007, /**< (Reserved; was PASSWORD) */
+// stun_message_integrity = 0x0008, /**< http://tools.ietf.org/html/rfc5389#page-34 */
+// stun_error_code = 0x0009, /**< http://tools.ietf.org/html/rfc5389#page-36 */
+// stun_unknown_attributes = 0x000A, /**< http://tools.ietf.org/html/rfc5389#page-38 */
+// stun_reflected_from = 0x000B, /**< (Reserved; was REFLECTED-FROM) */
+// stun_realm = 0x0014, /**< http://tools.ietf.org/html/rfc5389#page-38 */
+// stun_nonce = 0x0015, /**< http://tools.ietf.org/html/rfc5389#page-38 */
+// stun_xor_mapped_address = 0x0020, /**< http://tools.ietf.org/html/rfc5389#page-33 */
+//
+// /* === RFC 5389 - Comprehension-optional range (0x8000-0xFFFF) */
+// stun_software = 0x8022, /**< http://tools.ietf.org/html/rfc5389#page-39 */
+// stun_alternate_server = 0x8023, /**< http://tools.ietf.org/html/rfc5389#page-39 */
+// stun_fingerprint = 0x8028, /**< http://tools.ietf.org/html/rfc5389#page-36 */
+//
+// /* === draft-ietf-behave-turn-16 */
+// stun_channel_number = 0x000C, /**< draft-ietf-behave-turn-16 - CHANNEL-NUMBER */
+// stun_lifetime = 0x000D, /**< draft-ietf-behave-turn-16 - LIFETIME */
+// stun_reserved2 = 0x0010, /**< draft-ietf-behave-turn-16 - Reserved (was BANDWIDTH) */
+// stun_xor_peer_address = 0x0012, /**< draft-ietf-behave-turn-16 - XOR-PEER-ADDRESS */
+// stun_data = 0x0013, /**< draft-ietf-behave-turn-16 - DATA */
+// stun_xor_relayed_address = 0x0016, /**< draft-ietf-behave-turn-16 - XOR-RELAYED-ADDRESS */
+// stun_even_port = 0x0018, /**< draft-ietf-behave-turn-16 - EVEN-PORT */
+// stun_requested_transport = 0x0019, /**< draft-ietf-behave-turn-16 - REQUESTED-TRANSPORT */
+// stun_dont_fragment = 0x001A, /**< draft-ietf-behave-turn-16 - DONT-FRAGMENT */
+// stun_reserved3 = 0x0021, /**< draft-ietf-behave-turn-16 - Reserved (was TIMER-VAL) */
+// stun_reservation_token = 0x0022, /**< draft-ietf-behave-turn-16 - RESERVATION-TOKEN */
+//
+// /* RFC 5245 */
+// stun_ice_priority = 0x0024, /**< 21.2. STUN Attributes */
+// stun_ice_use_candidate = 0x0025, /**< 21.2. STUN Attributes */
+// stun_ice_controlled = 0x8029, /**< 21.2. STUN Attributes */
+// stun_ice_controlling = 0x802A, /**< 21.2. STUN Attributes */
+//}
+//tnet_stun_attr_type_t;
+//
+//
+///**@ingroup tnet_stun_group
+// RFC 5389 - 15. STUN Attributes
+//*/
+//typedef struct tnet_stun_attribute_s {
+// TSK_DECLARE_OBJECT;
+// /*
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Type | Length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Value (variable) ....
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// */
+// tnet_stun_attr_type_t type;
+// uint16_t length;
+//}
+//tnet_stun_attr_t;
+//
+//typedef tsk_list_t tnet_stun_attributes_L_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_def_t;
+//
+//#define TNET_STUN_DECLARE_ATTRIBUTE tnet_stun_attr_t attribute
+//
+//
+///**@ingroup tnet_stun_group
+// *RFC 5389 - 15.1. MAPPED-ADDRESS
+// */
+//typedef struct tnet_stun_attribute_mapped_addr_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// /*
+// 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 0 0 0 0 0 0 0| Family | Port |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// | Address (32 bits or 128 bits) |
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// */
+// tnet_stun_addr_family_t family;
+// uint16_t port;
+// uint8_t address[16];
+//}
+//tnet_stun_attribute_mapped_addr_t;
+//
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_mapped_addr_def_t;
+//
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS
+//*/
+//typedef struct tnet_stun_attribute_xmapped_addr_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// /*
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |x x x x x x x x| Family | X-Port |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | X-Address (Variable)
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// */
+// tnet_stun_addr_family_t family;
+// uint16_t xport;
+// uint8_t xaddress[16];
+//}
+//tnet_stun_attribute_xmapped_addr_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_xmapped_addr_def_t;
+//
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.3. USERNAME.
+//*/
+//typedef struct tnet_stun_attribute_username_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// char* value;
+//}
+//tnet_stun_attribute_username_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_username_def_t;
+//
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.4. MESSAGE-INTEGRITY.
+//*/
+//typedef struct tnet_stun_attribute_integrity_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// tsk_sha1digest_t sha1digest;
+//}
+//tnet_stun_attribute_integrity_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_integrity_def_t;
+//
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.5. FINGERPRINT.
+//*/
+//typedef struct tnet_stun_attribute_fingerprint_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// uint32_t value;
+//}
+//tnet_stun_attribute_fingerprint_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_fingerprint_def_t;
+//
+///**@ingroup tnet_stun_group
+// *RFC 5389 - 15.6. ERROR-CODE
+//*/
+//typedef struct tnet_stun_attribute_errorcode_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+// /*
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Reserved, should be 0 |Class| Number |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Reason Phrase (variable) ..
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// */
+// uint8_t _class;
+// uint8_t number;
+// char* reason_phrase;
+//}
+//tnet_stun_attribute_errorcode_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_errorcode_def_t;
+//
+//
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.7. REALM. */
+//typedef struct tnet_stun_attribute_realm_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// char* value;
+//}
+//tnet_stun_attribute_realm_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_realm_def_t;
+//
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.8. NONCE. */
+//typedef struct tnet_stun_attribute_nonce_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// char* value;
+//}
+//tnet_stun_attribute_nonce_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_nonce_def_t;
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.9. UNKNOWN-ATTRIBUTES. */
+//typedef struct tnet_stun_attribute_unknowns_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// tsk_buffer_t *value;
+//}
+//tnet_stun_attribute_unknowns_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_unknowns_def_t;
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.10. SOFTWARE. */
+//typedef struct tnet_stun_attribute_software_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// char *value;
+//}
+//tnet_stun_attribute_software_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_software_def_t;
+//
+///**@ingroup tnet_stun_group
+//* RFC 5389 - 15.11. ALTERNATE-SERVER. */
+//typedef struct tnet_stun_attribute_altserver_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// tnet_stun_addr_family_t family;
+// uint16_t port;
+// uint8_t server[128];
+//}
+//tnet_stun_attribute_altserver_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_altserver_def_t;
+//
+///**@ingroup tnet_stun_group
+//* RFC 5245 - 19.1. New Attributes */
+//typedef struct tnet_stun_attribute_ice_priority_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+// uint32_t value;
+//}
+//tnet_stun_attribute_ice_priority_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_ice_priority_def_t;
+//
+///**@ingroup tnet_stun_group
+//* RFC 5245 - 19.1. New Attributes */
+//typedef struct tnet_stun_attribute_ice_use_candidate_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//}
+//tnet_stun_attribute_ice_use_candidate_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_ice_use_candidate_def_t;
+//
+///**@ingroup tnet_stun_group
+//* RFC 5245 - 19.1. New Attributes */
+//typedef struct tnet_stun_attribute_ice_controlled_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+// uint64_t value;
+//}
+//tnet_stun_attribute_ice_controlled_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_ice_controlled_def_t;
+//
+///**@ingroup tnet_stun_group
+//* RFC 5245 - 19.1. New Attributes */
+//typedef struct tnet_stun_attribute_ice_controlling_s {
+// TNET_STUN_DECLARE_ATTRIBUTE;
+// uint64_t value;
+//}
+//tnet_stun_attribute_ice_controlling_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_ice_controlling_def_t;
+//
+//tnet_stun_attr_t* tnet_stun_attribute_deserialize(const void* data, tsk_size_t size);
+//int tnet_stun_attribute_serialize(const tnet_stun_attr_t* attribute, tsk_buffer_t *output);
+//void tnet_stun_attribute_pad(const tnet_stun_attr_t* attribute, tsk_buffer_t *output);
+//
+//
+//
+//
+//tnet_stun_attr_t* tnet_stun_attribute_create();
+//TINYNET_API tnet_stun_attribute_mapped_addr_t* tnet_stun_attribute_mapped_address_create(const void* payload, tsk_size_t payload_size);
+//TINYNET_API tnet_stun_attribute_xmapped_addr_t* tnet_stun_attribute_xmapped_address_create(const void* payload, tsk_size_t payload_size);
+//TINYNET_API tnet_stun_attribute_username_t* tnet_stun_attribute_username_create(const void* payload, tsk_size_t payload_size);
+//TINYNET_API tnet_stun_attribute_integrity_t* tnet_stun_attribute_integrity_create(const void* payload, tsk_size_t payload_size);
+//TINYNET_API tnet_stun_attribute_fingerprint_t* tnet_stun_attribute_fingerprint_create(uint32_t fingerprint);
+//TINYNET_API tnet_stun_attribute_errorcode_t* tnet_stun_attribute_errorcode_create(const void* payload, tsk_size_t payload_size);
+//TINYNET_API tnet_stun_attribute_realm_t* tnet_stun_attribute_realm_create(const void* payload, tsk_size_t payload_size);
+//TINYNET_API tnet_stun_attribute_nonce_t* tnet_stun_attribute_nonce_create(const void* payload, tsk_size_t payload_size);
+//TINYNET_API tnet_stun_attribute_unknowns_t* tnet_stun_attribute_unknowns_create(const void* payload, tsk_size_t payload_size);
+//TINYNET_API tnet_stun_attribute_software_t* tnet_stun_attribute_software_create(const void* payload, tsk_size_t payload_size);
+//TINYNET_API tnet_stun_attribute_altserver_t* tnet_stun_attribute_altserver_create(const void* payload, tsk_size_t payload_size);
+//TINYNET_API tnet_stun_attribute_ice_priority_t* tnet_stun_attribute_ice_priority_create(uint32_t value);
+//TINYNET_API tnet_stun_attribute_ice_use_candidate_t* tnet_stun_attribute_ice_use_candidate_create();
+//TINYNET_API tnet_stun_attribute_ice_controlled_t* tnet_stun_attribute_ice_controlled_create(uint64_t value);
+//TINYNET_API tnet_stun_attribute_ice_controlling_t* tnet_stun_attribute_ice_controlling_create(uint64_t value);
+//
+//
+//TNET_END_DECLS
+//
+//#endif /* TNET_STUN_ATTRIBUTE_H */
+//
diff --git a/tinyNET/src/stun/tnet_stun_binding.c b/tinyNET/src/stun/tnet_stun_binding.c
new file mode 100644
index 0000000..6455751
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_binding.c
@@ -0,0 +1,127 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#include "stun/tnet_stun_binding.h"
+#include "stun/tnet_stun_pkt.h"
+#include "stun/tnet_stun_attr.h"
+#include "tnet_utils.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+int tnet_stun_binding_create(tnet_fd_t fd, enum tnet_socket_type_e socket_type, const char* pc_server_address, tnet_port_t server_port, const char* pc_username, const char* pc_password, tnet_stun_binding_t** pp_bind)
+{
+ extern const tsk_object_def_t *tnet_stun_binding_def_t;
+ static long __unique_id = 0;
+
+ if (!pp_bind) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!(*pp_bind = tsk_object_new(tnet_stun_binding_def_t))) {
+ TSK_DEBUG_ERROR("Failed to create STUN binding object");
+ return -2;
+ }
+ tsk_atomic_inc(&__unique_id);
+ (*pp_bind)->id = __unique_id;
+ (*pp_bind)->localFD = fd;
+ (*pp_bind)->socket_type = socket_type;
+ (*pp_bind)->p_username = tsk_strdup(pc_username);
+ (*pp_bind)->p_password = tsk_strdup(pc_password);
+
+ if (pc_server_address && server_port) {
+ int ret;
+ if ((ret = tnet_sockaddr_init(pc_server_address, server_port, socket_type, &(*pp_bind)->addr_server))) {
+ TSK_OBJECT_SAFE_FREE((*pp_bind));
+ TSK_DEBUG_ERROR("Failed to init STUN server address");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+int tnet_stun_binding_create_req(const struct tnet_stun_binding_s* pc_self, struct tnet_stun_pkt_s **pp_req)
+{
+ int ret;
+ if (!pc_self || !pp_req) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_binding_request, pp_req))) {
+ TSK_DEBUG_ERROR("Failed to create STUN Bind request");
+ goto bail;
+ }
+ // add attributes
+ (*pp_req)->opt.dontfrag = 0;
+ ret = tnet_stun_pkt_attrs_add(*pp_req,
+ TNET_STUN_PKT_ATTR_ADD_SOFTWARE_ZT(kStunSoftware),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ if (pc_self->p_username && pc_self->p_realm && pc_self->p_nonce) {
+ if ((ret = tnet_stun_pkt_auth_prepare(*pp_req, pc_self->p_username, pc_self->p_password, pc_self->p_realm, pc_self->p_nonce))) {
+ goto bail;
+ }
+ }
+
+bail:
+ if (ret) {
+ TSK_OBJECT_SAFE_FREE(*pp_req);
+ }
+ return ret;
+}
+
+static tsk_object_t* tnet_stun_binding_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_stun_binding_t *p_bind = (tnet_stun_binding_t *)self;
+ if (p_bind) {
+ }
+ return self;
+}
+static tsk_object_t* tnet_stun_binding_dtor(tsk_object_t * self)
+{
+ tnet_stun_binding_t *p_bind = (tnet_stun_binding_t *)self;
+ if (p_bind) {
+ TSK_DEBUG_INFO("*** STUN BINDING destroyed ***");
+ TSK_FREE(p_bind->p_username);
+ TSK_FREE(p_bind->p_password);
+ TSK_FREE(p_bind->p_realm);
+ TSK_FREE(p_bind->p_nonce);
+
+ TSK_OBJECT_SAFE_FREE(p_bind->p_maddr);
+ TSK_OBJECT_SAFE_FREE(p_bind->p_xmaddr);
+ }
+ return self;
+}
+static int tnet_stun_binding_cmp(const tsk_object_t *_bind1, const tsk_object_t *_bind2)
+{
+ const tnet_stun_binding_t *pc_bind1 = (const tnet_stun_binding_t *)_bind1;
+ const tnet_stun_binding_t *pc_bind2 = (const tnet_stun_binding_t *)_bind2;
+
+ return (pc_bind1 && pc_bind2) ? (int)(pc_bind1->id - pc_bind2->id) : (int)(pc_bind1 - pc_bind2);
+}
+static const tsk_object_def_t tnet_stun_binding_def_s = {
+ sizeof(tnet_stun_binding_t),
+ tnet_stun_binding_ctor,
+ tnet_stun_binding_dtor,
+ tnet_stun_binding_cmp,
+};
+const tsk_object_def_t *tnet_stun_binding_def_t = &tnet_stun_binding_def_s;
diff --git a/tinyNET/src/stun/tnet_stun_binding.h b/tinyNET/src/stun/tnet_stun_binding.h
new file mode 100644
index 0000000..d7e2ae4
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_binding.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_STUN_BINDING_H
+#define TNET_STUN_BINDING_H
+
+#include "tinynet_config.h"
+#include "tnet_socket.h"
+#include "stun/tnet_stun_types.h"
+#include "stun/tnet_stun_attr.h"
+
+#include "tsk_object.h"
+#include "tsk_list.h"
+
+TNET_BEGIN_DECLS
+
+struct tnet_stun_pkt_s;
+
+typedef struct tnet_stun_binding_s {
+ TSK_DECLARE_OBJECT;
+
+ //! A unique id to identify this binding.
+ tnet_stun_binding_id_t id;
+
+ //! The username to authenticate to the STUN server.
+ char* p_username;
+ //! The password to authenticate to the STUN server.
+ char* p_password;
+ //! The realm.
+ char* p_realm;
+ //! The nonce.
+ char* p_nonce;
+ //! Local file descriptor for which to get server reflexive address.
+ tnet_fd_t localFD;
+ //! The type of the bound socket.
+ enum tnet_socket_type_e socket_type;
+ //! The address of the STUN server.
+ struct sockaddr_storage addr_server;
+ //! Server reflexive address of the local socket(STUN1 as per RFC 3489).
+ struct tnet_stun_attr_address_s *p_maddr;
+ //! XORed server reflexive address (STUN2 as per RFC 5389).
+ struct tnet_stun_attr_address_s *p_xmaddr;
+}
+tnet_stun_binding_t;
+typedef tsk_list_t tnet_stun_bindings_L_t;
+
+int tnet_stun_binding_create(tnet_fd_t fd, enum tnet_socket_type_e socket_type, const char* pc_server_address, tnet_port_t server_port, const char* pc_username, const char* pc_password, tnet_stun_binding_t** pp_bind);
+int tnet_stun_binding_create_req(const struct tnet_stun_binding_s* pc_self, struct tnet_stun_pkt_s **pp_req);
+
+TNET_END_DECLS
+
+#endif /* TNET_STUN_BINDING_H */
diff --git a/tinyNET/src/stun/tnet_stun_message.c b/tinyNET/src/stun/tnet_stun_message.c
new file mode 100644
index 0000000..25d29a5
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_message.c
@@ -0,0 +1,495 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_stun_message.c
+// * @brief STUN2 (RFC 5389) message parser.
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#include "tnet_stun_message.h"
+//
+//#include "tnet_stun.h"
+//
+//#include "../tnet_types.h"
+//#include "../tnet_endianness.h"
+//#include "../turn/tnet_turn_attribute.h"
+//#include "stun/tnet_stun_types.h"
+//
+//#include "tsk_memory.h"
+//#include "tsk_hmac.h"
+//#include "tsk_string.h"
+//#include "tsk_ppfcs32.h"
+//
+//#include <string.h>
+//
+//static int __pred_find_attribute_by_type(const tsk_list_item_t *item, const void *att_type)
+//{
+// if(item && item->data) {
+// tnet_stun_attr_t *att = item->data;
+// tnet_stun_attr_type_t type = *((tnet_stun_attr_type_t*)att_type);
+// return (att->type - type);
+// }
+// return -1;
+//}
+//
+///**@ingroup tnet_stun_group
+//* Creates new STUN message.
+//* @retval @ref tnet_stun_pkt_t object.
+//* @sa tnet_stun_message_create_null.
+//*/
+//
+//tnet_stun_pkt_t* tnet_stun_message_create(const char* username, const char* password)
+//{
+// return tsk_object_new(tnet_stun_message_def_t, username, password);
+//}
+//
+///**@ingroup tnet_stun_group
+//* Creates new STUN message.
+//* @retval @ref tnet_stun_pkt_t object.
+//* @sa tnet_stun_message_create.
+//*/
+//tnet_stun_pkt_t* tnet_stun_message_create_null()
+//{
+// return tnet_stun_message_create(tsk_null, tsk_null);
+//}
+//
+//#define SERIALIZE_N_ADD_ATTRIBUTE(att_name, payload, payload_size) \
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_##att_name##_create(payload, payload_size); \
+// tnet_stun_attribute_serialize(attribute, output); \
+// tnet_stun_attribute_pad(attribute, output); \
+// TSK_OBJECT_SAFE_FREE(attribute);
+//
+///**@ingroup tnet_stun_group
+// * Serializes a STUN message as binary data.
+// * @param [in,out] self The STUN message to serialize.
+// * @retval A buffer holding the binary data (result) if serialization succeed and zero otherwise.
+//**/
+//tsk_buffer_t* tnet_stun_pkt_serialize(const tnet_stun_pkt_t *self)
+//{
+// tsk_buffer_t *output = 0;
+// tnet_stun_attr_t *attribute;
+// unsigned compute_integrity = self->integrity;
+//
+// if(!self) {
+// goto bail;
+// }
+//
+// output = tsk_buffer_create_null();
+//
+// /* RFC 5389 - 6. STUN Message Structure
+// 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 0| STUN Message Type | Message Length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Magic Cookie |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// | Transaction ID (96 bits) |
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// */
+//
+// /* STUN Message Type
+// */
+// {
+// uint16_t type = tnet_htons(self->type);
+// tsk_buffer_append(output, &(type), 2);
+// }
+//
+// /* Message Length ==> Will be updated after attributes have been added. */
+// {
+// static const uint16_t length = 0;
+// tsk_buffer_append(output, &(length), 2);
+// }
+//
+// /* Magic Cookie
+// */
+// {
+// uint32_t cookie = tnet_htonl(self->cookie);
+// tsk_buffer_append(output, &(cookie), 4);
+// }
+//
+//
+// /* Transaction ID (96 bits==>16bytes)
+// */
+// tsk_buffer_append(output, self->transac_id, TNET_STUN_TRANSACID_SIZE);
+//
+// /* DONT-FRAGMENT
+// */
+// if(self->dontfrag) {
+// /*attribute = (tnet_stun_attr_t *)tnet_turn_attribute_dontfrag_create();
+// tnet_stun_attribute_serialize(attribute, output);
+// TSK_OBJECT_SAFE_FREE(attribute);*/
+// }
+//
+// /* AUTHENTICATION */
+// if(self->realm && self->nonce) { // long term
+// SERIALIZE_N_ADD_ATTRIBUTE(realm, self->realm, tsk_strlen(self->realm));
+// SERIALIZE_N_ADD_ATTRIBUTE(nonce, self->nonce, tsk_strlen(self->nonce));
+//
+// compute_integrity = !self->nointegrity;
+// }
+// else if(self->password) { // short term
+// compute_integrity = !self->nointegrity;
+// }
+//
+// if(compute_integrity && self->username) {
+// SERIALIZE_N_ADD_ATTRIBUTE(username, self->username, tsk_strlen(self->username));
+// }
+//
+// /*=== Attributes === */
+// {
+// tsk_list_item_t *item;
+// tsk_list_foreach(item, self->attributes) {
+// attribute = item->data;
+// tnet_stun_attribute_serialize(attribute, output);
+// tnet_stun_attribute_pad(attribute, output);
+// }
+// }
+//
+// /* Message Length: The message length MUST contain the size, in bytes, of the message
+// not including the 20-byte STUN header.
+// */
+// {
+// // compute length for 'MESSAGE-INTEGRITY'
+// // will be computed again to store the correct value
+// uint16_t length = (output->size) - kStunAttrHdrSizeInOctets;
+//#if 0
+// if(self->fingerprint) {
+// length += (2/* Type */ + 2 /* Length */+ 4 /* FINGERPRINT VALUE*/);
+// }
+//#endif
+//
+// if(compute_integrity) {
+// length += (2/* Type */ + 2 /* Length */+ TSK_SHA1_DIGEST_SIZE /* INTEGRITY VALUE*/);
+// }
+//
+// *(((uint16_t*)output->data)+1) = tnet_htons(length);
+// }
+//
+// /* MESSAGE-INTEGRITY */
+// if(compute_integrity) {
+// /* RFC 5389 - 15.4. MESSAGE-INTEGRITY
+// The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [RFC2104] of the STUN message.
+//
+// For long-term credentials ==> key = MD5(username ":" realm ":" SASLprep(password))
+// For short-term credentials ==> key = SASLprep(password)
+// */
+//
+// tsk_sha1digest_t hmac;
+//
+// if(self->username && self->realm && self->password) { // long term
+// char* keystr = tsk_null;
+// tsk_md5digest_t md5;
+// tsk_sprintf(&keystr, "%s:%s:%s", self->username, self->realm, self->password);
+// TSK_MD5_DIGEST_CALC(keystr, tsk_strlen(keystr), md5);
+// hmac_sha1digest_compute(output->data, output->size, (const char*)md5, TSK_MD5_DIGEST_SIZE, hmac);
+//
+// TSK_FREE(keystr);
+// }
+// else { // short term
+// hmac_sha1digest_compute(output->data, output->size, self->password, tsk_strlen(self->password), hmac);
+// }
+//
+// SERIALIZE_N_ADD_ATTRIBUTE(integrity, hmac, TSK_SHA1_DIGEST_SIZE);
+// }
+//
+// // LENGTH
+// *(((uint16_t*)output->data) + 1) = tnet_htons((output->size - kStunAttrHdrSizeInOctets + (self->fingerprint ? 8 : 0)));
+//
+// /* FINGERPRINT */
+// if(self->fingerprint) { //JINGLE_ICE
+// /* RFC 5389 - 15.5. FINGERPRINT
+// The FINGERPRINT attribute MAY be present in all STUN messages. The
+// value of the attribute is computed as the CRC-32 of the STUN message
+// up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with
+// the 32-bit value 0x5354554e
+// */
+// uint32_t fingerprint = tsk_pppfcs32(TSK_PPPINITFCS32, output->data, output->size);
+// fingerprint ^= 0x5354554e;
+// fingerprint = tnet_htonl(fingerprint);
+//
+// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_fingerprint_create(fingerprint);
+// tnet_stun_attribute_serialize(attribute, output);
+// TSK_OBJECT_SAFE_FREE(attribute);
+// }
+//
+//bail:
+// return output;
+//}
+//
+//
+///**@ingroup tnet_stun_group
+// *
+// * Deserializes a STUN message from binary data.
+// *
+// * @param [in,out] data A pointer to the binary data.
+// * @param size The size of the binary data.
+// *
+// * @retval A STUN message if deserialization succeed or NULL otherwise.
+//**/
+//tnet_stun_pkt_t* tnet_stun_message_deserialize(const uint8_t *data, tsk_size_t size)
+//{
+// tnet_stun_pkt_t *message = 0;
+// uint8_t* dataPtr, *dataEnd;
+//
+//
+// if(!data || (size < kStunAttrHdrSizeInOctets) || !TNET_STUN_BUFF_IS_STUN2(data, size)) {
+// goto bail;
+// }
+//
+// dataPtr = (uint8_t*)data;
+// dataEnd = (dataPtr + size);
+//
+// message = tnet_stun_message_create_null();
+//
+// /* Message Type
+// */
+// message->type = (tnet_stun_pkt_type_t)tnet_ntohs_2(dataPtr);
+// dataPtr += 2;
+//
+// /* Message Length
+// */
+// message->length = tnet_ntohs_2(dataPtr);
+// dataPtr += 2;
+//
+// /* Check message validity
+// */
+// if((message->length + kStunAttrHdrSizeInOctets) != size) {
+// TSK_OBJECT_SAFE_FREE(message);
+// goto bail;
+// }
+//
+// /* Magic Cookie
+// ==> already set by the constructor and checked by @ref TNET_IS_STUN2
+// */
+// dataPtr += 4;
+//
+// /* Transaction ID
+// */
+// memcpy(message->transac_id, dataPtr, TNET_STUN_TRANSACID_SIZE);
+// dataPtr += TNET_STUN_TRANSACID_SIZE;
+//
+// /* == Parse attributes
+// */
+// while(dataPtr < dataEnd) {
+// tnet_stun_attr_t *attribute = tnet_stun_attribute_deserialize(dataPtr, (dataEnd - dataPtr));
+// if(attribute) {
+// tsk_size_t att_size = (attribute->length + 2 /* Type*/ + 2/* Length */);
+// att_size += (att_size & 0x03) ? 4-(att_size & 0x03) : 0; // Skip zero bytes used to pad the attribute.
+//
+// dataPtr += att_size;
+// tsk_list_push_back_data(message->attributes, (void**)&attribute);
+//
+// continue;
+// }
+// else {
+// continue;
+// }
+// }
+//
+//bail:
+// return message;
+//}
+//
+///**@ingroup tnet_stun_group
+//*/
+//tsk_bool_t tnet_stun_message_has_attribute(const tnet_stun_pkt_t *self, tnet_stun_attr_type_t type)
+//{
+// return (tnet_stun_message_get_attribute(self, type) != tsk_null);
+//}
+//
+///**@ingroup tnet_stun_group
+//* Adds an attribute to a STUN message.
+//* @param self The STUN message into which to add the attribute.
+//* @param attribute The attribute to add.
+//* @retval Zero if succeed and non-zero error code otherwise.
+//*/
+//int tnet_stun_message_add_attribute(tnet_stun_pkt_t *self, tnet_stun_attr_t** attribute)
+//{
+// if(self && attribute && *attribute) {
+// tsk_list_push_back_data(self->attributes, (void**)attribute);
+// return 0;
+// }
+// return -1;
+//}
+//
+///**@ingroup tnet_stun_group
+//*/
+//int tnet_stun_message_remove_attribute(tnet_stun_pkt_t *self, tnet_stun_attr_type_t type)
+//{
+// if(self && self->attributes) {
+// tsk_list_remove_item_by_pred(self->attributes, __pred_find_attribute_by_type, &type);
+// }
+// return 0;
+//}
+//
+//
+///**@ingroup tnet_stun_group
+//* Gets a STUN attribute from a message.
+//* @param self The message from which to get the attribute.
+//* @param type The type of the attribute to retrieve.
+//* @retval @ref tnet_stun_attr_t object if found and NULL otherwise.
+//*/
+//const tnet_stun_attr_t* tnet_stun_message_get_attribute(const tnet_stun_pkt_t *self, tnet_stun_attr_type_t type)
+//{
+// tnet_stun_attr_t* attribute;
+//
+// if(self && !TSK_LIST_IS_EMPTY(self->attributes)) {
+// tsk_list_item_t *item;
+// tsk_list_foreach(item, self->attributes) {
+// if((attribute = item->data) && attribute->type == type) {
+// return attribute;
+// }
+// }
+// }
+// return 0;
+//}
+//
+///**@ingroup tnet_stun_group
+//* Gets the STUN error-code attribute value from the message.
+//* @param self The STUN message from which to get the error code.
+//* @retval The error code if the message contain such attribute or -1 otherwise.
+//*/
+//short tnet_stun_message_get_errorcode(const tnet_stun_pkt_t *self)
+//{
+// const tnet_stun_attribute_errorcode_t* error = (const tnet_stun_attribute_errorcode_t*)tnet_stun_message_get_attribute(self, stun_error_code);
+// if(error) {
+// return ((error->_class*100) + error->number);
+// }
+// return -1;
+//}
+//
+///**@ingroup tnet_stun_group
+//* Gets the STUN @b realm attribute value from the message.
+//* @param self The STUN message from which to get the @b realm.
+//* @retval The @b realm as a string pointer code if the message contain such attribute or NULL otherwise.
+//*/
+//const char* tnet_stun_message_get_realm(const tnet_stun_pkt_t *self)
+//{
+// const tnet_stun_attribute_realm_t* realm = (const tnet_stun_attribute_realm_t*)tnet_stun_message_get_attribute(self, stun_realm);
+// if(realm) {
+// return realm->value;
+// }
+// return 0;
+//}
+//
+///**@ingroup tnet_stun_group
+//* Gets the STUN @b nonce attribute value from the message.
+//* @param self The STUN message from which to get the @b nonce.
+//* @retval The @b nonce as a string pointer code if the message contain such attribute or NULL otherwise.
+//*/
+//const char* tnet_stun_message_get_nonce(const tnet_stun_pkt_t *self)
+//{
+// const tnet_stun_attribute_nonce_t* nonce = (const tnet_stun_attribute_nonce_t*)tnet_stun_message_get_attribute(self, stun_nonce);
+// if(nonce) {
+// return nonce->value;
+// }
+// return 0;
+//}
+//
+///**@ingroup tnet_stun_group
+//* Gets the STUN @b lifetime attribute value from the message.
+//* @param self The STUN message from which to get the @b lifetime.
+//* @retval The @b lifetime (any positive value) if the message contain such attribute or -1 otherwise.
+//*/
+//int32_t tnet_stun_message_get_lifetime(const tnet_stun_pkt_t *self)
+//{
+// /*const tnet_turn_attribute_lifetime_t* lifetime = (const tnet_turn_attribute_lifetime_t*)tnet_stun_message_get_attribute(self, stun_lifetime);
+// if(lifetime) {
+// return lifetime->value;
+// }*/
+// return -1;
+//}
+//
+///**@ingroup tnet_stun_group
+//*/
+//tsk_bool_t tnet_stun_utils_transac_id_equals(const tnet_stun_transac_id_t id1, const tnet_stun_transac_id_t id2)
+//{
+// tsk_size_t i;
+// static const tsk_size_t size = sizeof(tnet_stun_transac_id_t);
+// for(i = 0; i < size; i++) {
+// if(id1[i] != id2[i]) {
+// return tsk_false;
+// }
+// }
+// return tsk_true;
+//}
+//
+//
+//
+//
+//
+//
+////=================================================================================================
+//// STUN2 MESSAGE object definition
+////
+//static tsk_object_t* tnet_stun_message_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_stun_pkt_t *message = self;
+// if(message) {
+// message->username = tsk_strdup(va_arg(*app, const char*));
+// message->password = tsk_strdup(va_arg(*app, const char*));
+//
+// message->cookie = kStunMagicCookieLong;
+// message->attributes = tsk_list_create();
+//
+// message->fingerprint = 1;
+// message->integrity = 0;
+//
+// {
+// // Create random transaction id
+// int i;
+// for(i = 0; i < sizeof(message->transac_id)/sizeof(message->transac_id[0]); ++i) {
+// message->transac_id[i] = rand();
+// }
+// }
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_stun_message_dtor(tsk_object_t * self)
+//{
+// tnet_stun_pkt_t *message = self;
+// if(message) {
+// TSK_FREE(message->username);
+// TSK_FREE(message->password);
+// TSK_FREE(message->realm);
+// TSK_FREE(message->nonce);
+//
+// TSK_OBJECT_SAFE_FREE(message->attributes);
+// }
+//
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_stun_message_def_s = {
+// sizeof(tnet_stun_pkt_t),
+// tnet_stun_message_ctor,
+// tnet_stun_message_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_stun_message_def_t = &tnet_stun_message_def_s;
+//
diff --git a/tinyNET/src/stun/tnet_stun_message.h b/tinyNET/src/stun/tnet_stun_message.h
new file mode 100644
index 0000000..70660f5
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_message.h
@@ -0,0 +1,246 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_stun_message.h
+// * @brief STUN2 (RFC 5389) message parser.
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#ifndef TNET_STUN_MESSAGE_H
+//#define TNET_STUN_MESSAGE_H
+//
+//#include "tinynet_config.h"
+//#include "stun/tnet_stun_attribute.h"
+//
+//#include "tsk_buffer.h"
+//
+//TNET_BEGIN_DECLS
+//
+//#define TNET_STUN_CLASS_REQUEST_MASK (0x0000)
+//#define TNET_STUN_CLASS_INDICATION_MASK (0x0010)
+//#define TNET_STUN_CLASS_SUCCESS_MASK (0x0100)
+//#define TNET_STUN_CLASS_ERROR_MASK (0x0110)
+//
+///**@ingroup tnet_stun_group
+//* @def TNET_STUN_MESSAGE_IS_REQUEST
+//* Checks whether the STUN message is a request or not.
+//*/
+///**@ingroup tnet_stun_group
+//* @def TNET_STUN_MESSAGE_IS_INDICATION
+//* Checks whether the STUN message is an indicaton message or not.
+//*/
+///**@ingroup tnet_stun_group
+//* @def TNET_STUN_PKT_RESP_IS_SUCCESS
+//* Checks whether the STUN message is a success response or not.
+//*/
+///**@ingroup tnet_stun_group
+//* @def TNET_STUN_PKT_RESP_IS_ERROR
+//* Checks whether the STUN message is an error response or not.
+//*/
+//#define TNET_STUN_MESSAGE_IS_REQUEST(self) ((self) && (((self)->type & 0x0110) == TNET_STUN_CLASS_REQUEST_MASK))
+//#define TNET_STUN_MESSAGE_IS_RESPONSE(self) (TNET_STUN_PKT_RESP_IS_SUCCESS((self)) || TNET_STUN_PKT_RESP_IS_ERROR((self)))
+//#define TNET_STUN_MESSAGE_IS_INDICATION(self) ((self) && (((self)->type & 0x0110) == TNET_STUN_CLASS_INDICATION_MASK))
+//#define TNET_STUN_PKT_RESP_IS_SUCCESS(self) ((self) && (((self)->type & 0x0110) == TNET_STUN_CLASS_SUCCESS_MASK))
+//#define TNET_STUN_PKT_RESP_IS_ERROR(self) ((self) && (((self)->type & 0x0110) == TNET_STUN_CLASS_ERROR_MASK))
+//
+///**@ingroup tnet_stun_group
+// * Checks if the pointer to the buffer hold a STUN header by checking that it starts with 0b00 and contain the magic cookie.
+// * As per RFC 5389 subclause 19: Explicitly point out that the most significant 2 bits of STUN are
+// * 0b00, allowing easy differentiation with RTP packets when used with ICE.
+// * As per RFC 5389 subclause 6: The magic cookie field MUST contain the fixed value 0x2112A442 in
+// * network byte order.
+// *
+// * @param PU8 The pointer to the buffer holding the STUN raw data.
+//**/
+//#define TNET_STUN_BUFF_IS_STUN2(PU8, SIZE) \
+// ( \
+// ((PU8)) && \
+// ((SIZE) >= kStunAttrHdrSizeInOctets) && \
+// (((PU8)[0] & 0xc0) == 0x00) && \
+// ( PU8[4] == 0x21 && PU8[5] == 0x12 && PU8[6] == 0xA4 && PU8[7] == 0x42 ) \
+// )
+//#define TNET_IS_STUN2 TNET_STUN_BUFF_IS_STUN2 // for backward compatibility
+//
+///**@ingroup tnet_stun_group
+// * STUN trasactionn ID size (96bits = 12bytes).
+//*/
+//#define TNET_STUN_TRANSACID_SIZE 12
+//
+///**@ingroup tnet_stun_group
+// * Defines an alias representing the STUN transaction id type.
+//**/
+//typedef uint8_t tnet_stun_transac_id_t[TNET_STUN_TRANSACID_SIZE];
+//
+///**@ingroup tnet_stun_group
+// * List of all supported STUN classes as per RFC 5389 subcaluse 6.
+//**/
+//typedef enum tnet_stun_class_type_e {
+// stun_class_request = 0x00, /**< Request class: 0b00 */
+// stun_class_indication = 0x01, /**< Indication class: 0b01 */
+// stun_class_success_response = 0x02, /**< Success response class: 0b10 */
+// stun_class_error_response = 0x03, /**< Error/failure response class: 0b11 */
+//}
+//tnet_stun_class_type_t;
+//
+///**@ingroup tnet_stun_group
+// * List of all supported STUN methods.
+// * RFC 5389 only define one method(Bining). All other methods have been defined
+// * by TURN (draft-ietf-behave-turn-16 and draft-ietf-behave-turn-tcp-05).
+//**/
+//typedef enum tnet_stun_method_type_e {
+// stun_method_binding = 0x0001, /**< RFC 5389 - Binding method: 0b000000000001 */
+//
+// stun_method_allocate = 0x0003, /**< draft-ietf-behave-turn-16 - Allocate (only request/response semantics defined) */
+// stun_method_refresh = 0x0004, /**< draft-ietf-behave-turn-16 - Refresh (only request/response semantics defined) */
+// stun_method_send = 0x0006, /**< draft-ietf-behave-turn-16 - Send (only indication semantics defined) */
+// stun_method_data = 0x0007, /**< draft-ietf-behave-turn-16 - Data (only indication semantics defined) */
+// stun_method_createpermission = 0x0008, /**< draft-ietf-behave-turn-16 - CreatePermission (only request/response semantics defined */
+// stun_method_channelbind = 0x0009, /**< draft-ietf-behave-turn-16 - ChannelBind (only request/response semantics defined) */
+//}
+//tnet_stun_method_type_t;
+//
+///**@ingroup tnet_stun_group
+//* List of all supported STUN types.
+//*/
+//typedef enum tnet_stun_pkt_type_e {
+// /* RFC 5389 - 6. STUN Message Structure
+//
+// The message type defines the message class (request, success
+// response, failure response, or indication) and the message method
+// (the primary function) of the STUN message. Although there are four
+// message classes, there are only two types of transactions in STUN:
+// request/response transactions (which consist of a request message and
+// a response message) and indication transactions (which consist of a
+// single indication message). Response classes are split into error
+// and success responses to aid in quickly processing the STUN message.
+//
+// The message type field is decomposed further into the following
+// structure:
+//
+// 0 1
+// 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+// +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
+// |M |M |M|M|M|C|M|M|M|C|M|M|M|M|
+// |11|10|9|8|7|1|6|5|4|0|3|2|1|0|
+// +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
+// */
+// stun_binding_request = (stun_method_binding | TNET_STUN_CLASS_REQUEST_MASK),
+// stun_binding_indication = (stun_method_binding | TNET_STUN_CLASS_INDICATION_MASK),
+// stun_binding_success_response = (stun_method_binding | TNET_STUN_CLASS_SUCCESS_MASK),
+// stun_binding_error_response = (stun_method_binding | TNET_STUN_CLASS_ERROR_MASK),
+//
+// stun_allocate_request = (stun_method_allocate | TNET_STUN_CLASS_REQUEST_MASK),
+// stun_allocate_indication = (stun_method_allocate | TNET_STUN_CLASS_INDICATION_MASK),
+// stun_allocate_success_response = (stun_method_allocate | TNET_STUN_CLASS_SUCCESS_MASK),
+// stun_allocate_error_response = (stun_method_allocate | TNET_STUN_CLASS_ERROR_MASK),
+//
+// stun_refresh_request = (stun_method_refresh | TNET_STUN_CLASS_REQUEST_MASK),
+// stun_refresh_indication = (stun_method_refresh | TNET_STUN_CLASS_INDICATION_MASK),
+// stun_refresh_success_response = (stun_method_refresh | TNET_STUN_CLASS_SUCCESS_MASK),
+// stun_refresh_error_response = (stun_method_refresh | TNET_STUN_CLASS_ERROR_MASK),
+//
+// stun_send_indication = (stun_method_send | TNET_STUN_CLASS_INDICATION_MASK),
+//
+// stun_data_indication = (stun_method_data | TNET_STUN_CLASS_INDICATION_MASK),
+//
+// stun_createpermission_request = (stun_method_createpermission | TNET_STUN_CLASS_REQUEST_MASK),
+// stun_createpermission_indication = (stun_method_createpermission | TNET_STUN_CLASS_INDICATION_MASK),
+// stun_createpermission_success_response = (stun_method_createpermission | TNET_STUN_CLASS_SUCCESS_MASK),
+// stun_createpermission_error_response = (stun_method_createpermission | TNET_STUN_CLASS_ERROR_MASK),
+//
+// stun_channelbind_request = (stun_method_channelbind | TNET_STUN_CLASS_REQUEST_MASK),
+// stun_channelbind_indication = (stun_method_channelbind | TNET_STUN_CLASS_INDICATION_MASK),
+// stun_channelbind_success_response = (stun_method_channelbind | TNET_STUN_CLASS_SUCCESS_MASK),
+// stun_channelbind_error_response = (stun_method_channelbind | TNET_STUN_CLASS_ERROR_MASK),
+//}
+//tnet_stun_pkt_type_t;
+//
+///**@ingroup tnet_stun_group
+// *
+// * STUN Message structure as per RFC 5389 subclause 6.
+// * http://tools.ietf.org/html/rfc5389#section-6
+//*/
+//typedef struct tnet_stun_pkt_s {
+// TSK_DECLARE_OBJECT;
+//
+// /*
+// 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 0| STUN Message Type | Message Length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Magic Cookie |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// | Transaction ID (96 bits) |
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// */
+//
+// tnet_stun_pkt_type_t type;
+// uint16_t length;
+// uint32_t cookie;
+// tnet_stun_transac_id_t transaction_id;
+//
+// unsigned fingerprint:1;
+// unsigned integrity:1;
+// unsigned dontfrag:1;
+// unsigned nointegrity:1;
+//
+// char* username;
+// char* password;
+// char* realm;
+// char* nonce;
+//
+// tnet_stun_attributes_L_t *attributes; /**< List of all attributes associated to this message */
+//}
+//tnet_stun_pkt_t;
+//
+//typedef tnet_stun_pkt_t tnet_stun_pkt_resp_t;
+//typedef tnet_stun_pkt_t tnet_stun_pkt_req_t;
+//
+//TINYNET_API tsk_buffer_t* tnet_stun_pkt_serialize(const tnet_stun_pkt_t *message);
+//tnet_stun_pkt_t* tnet_stun_message_deserialize(const uint8_t *data, tsk_size_t size);
+//tsk_bool_t tnet_stun_message_has_attribute(const tnet_stun_pkt_t *self, tnet_stun_attr_type_t type);
+//TINYNET_API int tnet_stun_message_add_attribute(tnet_stun_pkt_t *self, tnet_stun_attr_t** attribute);
+//int tnet_stun_message_remove_attribute(tnet_stun_pkt_t *self, tnet_stun_attr_type_t type);
+//const tnet_stun_attr_t* tnet_stun_message_get_attribute(const tnet_stun_pkt_t *self, tnet_stun_attr_type_t type);
+//short tnet_stun_message_get_errorcode(const tnet_stun_pkt_t *self);
+//const char* tnet_stun_message_get_realm(const tnet_stun_pkt_t *self);
+//const char* tnet_stun_message_get_nonce(const tnet_stun_pkt_t *self);
+//int32_t tnet_stun_message_get_lifetime(const tnet_stun_pkt_t *self);
+//tsk_bool_t tnet_stun_utils_transac_id_equals(const tnet_stun_transac_id_t id1, const tnet_stun_transac_id_t id2);
+//
+//
+//TINYNET_API tnet_stun_pkt_t* tnet_stun_message_create(const char* username, const char* password);
+//TINYNET_API tnet_stun_pkt_t* tnet_stun_message_create_null();
+//
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_message_def_t;
+//
+//
+//TNET_END_DECLS
+//
+//
+//#endif /* TNET_STUN_MESSAGE_H */
+//
diff --git a/tinyNET/src/stun/tnet_stun_pkt.c b/tinyNET/src/stun/tnet_stun_pkt.c
new file mode 100644
index 0000000..e4d559d
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_pkt.c
@@ -0,0 +1,751 @@
+/* Copyright (C) 2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#include "stun/tnet_stun_pkt.h"
+#include "stun/tnet_stun_utils.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_sha1.h"
+#include "tsk_hmac.h"
+#include "tsk_md5.h"
+#include "tsk_ppfcs32.h"
+#include "tsk_buffer.h"
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#if !defined(PRINT_DESTROYED_MSG)
+# define PRINT_DESTROYED_MSG 0
+#endif
+
+int tnet_stun_pkt_create(tnet_stun_pkt_type_t e_type, uint16_t u_length, const tnet_stun_transac_id_t* pc_transac_id, tnet_stun_pkt_t** pp_attr)
+{
+ extern const tsk_object_def_t *tnet_stun_pkt_def_t;
+ if (!pp_attr) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!(*pp_attr = tsk_object_new(tnet_stun_pkt_def_t))) {
+ TSK_DEBUG_ERROR("Failed to create STUN pkt object");
+ return -2;
+ }
+ if (!((*pp_attr)->p_list_attrs = tsk_list_create())) {
+ TSK_OBJECT_SAFE_FREE(*pp_attr);
+ return -3;
+ }
+ if (pc_transac_id) {
+ memcpy((*pp_attr)->transac_id, *pc_transac_id, sizeof(tnet_stun_transac_id_t));
+ }
+ else {
+ tnet_stun_utils_transac_id_rand(&(*pp_attr)->transac_id);
+ }
+ (*pp_attr)->e_type = e_type;
+ (*pp_attr)->u_length = u_length;
+ return 0;
+}
+
+int tnet_stun_pkt_attr_add(tnet_stun_pkt_t* p_self, tnet_stun_attr_t** pp_attr)
+{
+ if (!p_self || !pp_attr || !*pp_attr) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_list_push_back_data(p_self->p_list_attrs, (void**)pp_attr);
+ return 0;
+}
+
+int tnet_stun_pkt_attrs_add(tnet_stun_pkt_t* p_self, ...)
+{
+ va_list ap;
+ int ret = 0;
+ tnet_stun_pkt_attr_add_t e_add_attr;
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ va_start(ap, p_self);
+
+ while ((e_add_attr = va_arg(ap, tnet_stun_pkt_attr_add_t)) != tnet_stun_pkt_attr_add_null) {
+ switch (e_add_attr) {
+ case tnet_stun_pkt_attr_add_vdata: {
+ // (enum tnet_stun_attr_type_e)(E_TYPE), (const uint8_t*)(P_DATA_PTR), (uint16_t)(U_DATA_SIZE)
+ enum tnet_stun_attr_type_e E_TYPE = va_arg(ap, enum tnet_stun_attr_type_e);
+ const uint8_t* P_DATA_PTR = va_arg(ap, const uint8_t*);
+ uint16_t U_DATA_SIZE = tsk_va_arg_u16(ap);
+ tnet_stun_attr_vdata_t *p_attr;
+ if ((ret = tnet_stun_attr_vdata_create(E_TYPE, P_DATA_PTR, U_DATA_SIZE, &p_attr))) {
+ goto bail;
+ }
+ if ((ret = tnet_stun_pkt_attr_add(p_self, (tnet_stun_attr_t**)&p_attr))) {
+ TSK_OBJECT_SAFE_FREE(p_attr);
+ goto bail;
+ }
+ break;
+ }
+ case tnet_stun_pkt_attr_add_address: {
+ // (enum tnet_stun_attr_type_e)(E_TYPE), (enum tnet_stun_address_family_e)(E_FAMILY), (uint16_t)(U_PORT), (const tnet_stun_addr_t*)PC_ADDR_PTR
+ enum tnet_stun_attr_type_e E_TYPE = va_arg(ap, enum tnet_stun_attr_type_e);
+ enum tnet_stun_address_family_e E_FAMILY = va_arg(ap, enum tnet_stun_address_family_e);
+ uint16_t U_PORT = tsk_va_arg_u16(ap);
+ const tnet_stun_addr_t* PC_ADDR_PTR = va_arg(ap, const tnet_stun_addr_t*);
+ tnet_stun_attr_address_t *p_attr;
+ if ((ret = tnet_stun_attr_address_create(E_TYPE, E_FAMILY, U_PORT, PC_ADDR_PTR, &p_attr))) {
+ goto bail;
+ }
+ if ((ret = tnet_stun_pkt_attr_add(p_self, (tnet_stun_attr_t**)&p_attr))) {
+ TSK_OBJECT_SAFE_FREE(p_attr);
+ goto bail;
+ }
+ break;
+ }
+ case tnet_stun_pkt_attr_add_error_code: {
+ // (uint8_t)(U8_CLASS), (uint8_t)(U8_NUMBER), (const char*)(PC_REASON_STR)
+ uint8_t U8_CLASS = tsk_va_arg_u8(ap);
+ uint8_t U8_NUMBER = tsk_va_arg_u8(ap);
+ const char* PC_REASON_STR = va_arg(ap, const char*);
+ tnet_stun_attr_error_code_t *p_attr;
+ if ((ret = tnet_stun_attr_error_code_create(U8_CLASS, U8_NUMBER, PC_REASON_STR, (uint16_t)tsk_strlen(PC_REASON_STR), &p_attr))) {
+ goto bail;
+ }
+ if ((ret = tnet_stun_pkt_attr_add(p_self, (tnet_stun_attr_t**)&p_attr))) {
+ TSK_OBJECT_SAFE_FREE(p_attr);
+ goto bail;
+ }
+ break;
+ }
+ case tnet_stun_pkt_attr_add_unknown_attrs: {
+ // (...)
+ tsk_buffer_t* p_buffer = tsk_buffer_create_null();
+ tnet_stun_attr_vdata_t *p_attr;
+ uint16_t u_16;
+ if (!p_buffer) {
+ TSK_DEBUG_ERROR("Failed to create buffer");
+ ret = -4;
+ goto bail;
+ }
+ while ((e_add_attr = va_arg(ap, tnet_stun_pkt_attr_add_t)) != tnet_stun_pkt_attr_add_null) {
+ if (e_add_attr != tnet_stun_pkt_attr_add_unknown_attrs_val) {
+ TSK_OBJECT_SAFE_FREE(p_buffer);
+ TSK_DEBUG_ERROR("Arguments corrupted or invalid.");
+ ret = -3;
+ goto bail;
+ }
+ u_16 = tsk_va_arg_u16(ap);
+ tsk_buffer_append(p_buffer, &u_16, 2);
+ }
+ if ((ret = tnet_stun_attr_vdata_create(tnet_stun_attr_type_unknown_attrs, p_buffer->data, (uint16_t)p_buffer->size, &p_attr))) {
+ TSK_OBJECT_SAFE_FREE(p_buffer);
+ goto bail;
+ }
+ TSK_OBJECT_SAFE_FREE(p_buffer);
+ if ((ret = tnet_stun_pkt_attr_add(p_self, (tnet_stun_attr_t**)&p_attr))) {
+ TSK_OBJECT_SAFE_FREE(p_attr);
+ goto bail;
+ }
+ break;
+ }
+ default: {
+ TSK_DEBUG_ERROR("Arguments corrupted or invalid.");
+ ret = -2;
+ goto bail;
+ }
+ }
+ }
+
+bail:
+ va_end(ap);
+ return ret;
+}
+
+int tnet_stun_pkt_attr_remove(struct tnet_stun_pkt_s* p_self, enum tnet_stun_attr_type_e e_type)
+{
+ tsk_list_item_t* pc_item;
+ tnet_stun_attr_t* pc_attr;
+ if (!p_self || !p_self->p_list_attrs) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+again:
+ tsk_list_foreach(pc_item, p_self->p_list_attrs) {
+ if ((pc_attr = (tnet_stun_attr_t*)pc_item->data)) {
+ if (pc_attr->hdr.e_type == e_type) {
+ tsk_list_remove_item(p_self->p_list_attrs, pc_item);
+ goto again;
+ }
+ }
+ }
+ return 0;
+}
+
+int tnet_stun_pkt_attr_find(const tnet_stun_pkt_t* pc_self, tnet_stun_attr_type_t e_type, tsk_size_t u_index, const tnet_stun_attr_t** ppc_attr)
+{
+ const tsk_list_item_t* pc_item;
+ const tnet_stun_attr_t* pc_attr;
+ if (!pc_self || !ppc_attr) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *ppc_attr = tsk_null;
+ tsk_list_foreach(pc_item, pc_self->p_list_attrs) {
+ if ((pc_attr = (const tnet_stun_attr_t*)pc_item->data)) {
+ if (pc_attr->hdr.e_type == e_type && !u_index--) {
+ *ppc_attr = pc_attr;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+tsk_bool_t tnet_stun_pkt_attr_exists(const tnet_stun_pkt_t* pc_self, tnet_stun_attr_type_t e_type)
+{
+ const tnet_stun_attr_t* pc_attr;
+ int ret = tnet_stun_pkt_attr_find(pc_self, e_type, 0, &pc_attr);
+ return (pc_attr && (ret == 0));
+}
+
+int tnet_stun_pkt_get_size_in_octetunits_without_padding(const tnet_stun_pkt_t* pc_self, tsk_size_t* p_size)
+{
+ const tsk_list_item_t* pc_item;
+ const tnet_stun_attr_t* pc_attr;
+ tsk_size_t n_size;
+ int ret;
+ if (!pc_self || !p_size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *p_size = kStunPktHdrSizeInOctets;
+ tsk_list_foreach(pc_item, pc_self->p_list_attrs) {
+ if ((pc_attr = (const tnet_stun_attr_t*)pc_item->data)) {
+ if ((ret = tnet_stun_attr_get_size_in_octetunits_without_padding(pc_attr, &n_size))) {
+ return ret;
+ }
+ *p_size += n_size;
+ }
+ }
+ if (pc_self->opt.fingerprint) {
+ *p_size += kStunAttrHdrSizeInOctets + 4;
+ }
+ if (pc_self->opt.dontfrag) {
+ *p_size += kStunAttrHdrSizeInOctets;
+ }
+ return 0;
+}
+
+int tnet_stun_pkt_get_size_in_octetunits_with_padding(const tnet_stun_pkt_t* pc_self, tsk_size_t* p_size)
+{
+ const tsk_list_item_t* pc_item;
+ const tnet_stun_attr_t* pc_attr;
+ tsk_size_t n_size;
+ int ret;
+ if (!pc_self || !p_size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *p_size = kStunPktHdrSizeInOctets;
+ tsk_list_foreach(pc_item, pc_self->p_list_attrs) {
+ if ((pc_attr = (const tnet_stun_attr_t*)pc_item->data)) {
+ if ((ret = tnet_stun_attr_get_size_in_octetunits_with_padding(pc_attr, &n_size))) {
+ return ret;
+ }
+ *p_size += n_size;
+ }
+ }
+ if (pc_self->opt.fingerprint) {
+ *p_size += kStunAttrHdrSizeInOctets + 4;
+ }
+ if (pc_self->opt.dontfrag) {
+ *p_size += kStunAttrHdrSizeInOctets;
+ }
+ return 0;
+}
+
+int tnet_stun_pkt_write_with_padding(const tnet_stun_pkt_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written)
+{
+ const tsk_list_item_t* pc_item;
+ const tnet_stun_attr_t* pc_attr;
+ tsk_size_t n_size;
+ int ret;
+ uint8_t *_p_buff_ptr = p_buff_ptr, *_p_msg_int_start;
+ if (!pc_self || !p_buff_ptr || !n_buff_size || !p_written) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = tnet_stun_pkt_get_size_in_octetunits_with_padding(pc_self, p_written))) {
+ return ret;
+ }
+ if ((n_buff_size < *p_written)) {
+ TSK_DEBUG_ERROR("Buffer too short: %u<%u", (unsigned)n_buff_size, (unsigned)*p_written);
+ return -1;
+ }
+
+ // write header
+ *((uint16_t*)&p_buff_ptr[0]) = tnet_htons((unsigned short)pc_self->e_type);
+ *((uint32_t*)&p_buff_ptr[4]) = (uint32_t)tnet_htonl(kStunMagicCookie);
+ memcpy(&p_buff_ptr[8], pc_self->transac_id, sizeof(pc_self->transac_id));
+
+ p_buff_ptr += kStunPktHdrSizeInOctets;
+ n_buff_size -= kStunPktHdrSizeInOctets;
+
+ // write attributes
+ tsk_list_foreach(pc_item, pc_self->p_list_attrs) {
+ if ((pc_attr = (const tnet_stun_attr_t*)pc_item->data)) {
+ if ((pc_attr->hdr.e_type == tnet_stun_attr_type_message_integrity)) {
+ continue; // because 'MESSAGE-INTEGRITY' must be the latest attribute
+ }
+ if ((ret = tnet_stun_attr_write_with_padding(&pc_self->transac_id, pc_attr, p_buff_ptr, n_buff_size, &n_size))) {
+ return ret;
+ }
+ p_buff_ptr += n_size;
+ n_buff_size -= n_size;
+ }
+ }
+
+ // DONT-FRAGMENT
+ if (pc_self->opt.dontfrag && tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_dont_fragment, &pc_attr) == 0 && !pc_attr) {
+ *((uint16_t*)&p_buff_ptr[0]) = tnet_htons(tnet_stun_attr_type_dont_fragment); // Type
+ *((uint16_t*)&p_buff_ptr[2]) = 0; // Length
+ p_buff_ptr += 4;
+ }
+
+ // MESSAGE-INTEGRITY
+ if (!tsk_strnullORempty(pc_self->p_pwd) && tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_message_integrity, &pc_attr) == 0 && pc_attr) {
+ /* RFC 5389 - 15.4. MESSAGE-INTEGRITY
+ The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [RFC2104] of the STUN message.
+
+ For long-term credentials ==> key = MD5(username ":" realm ":" SASLprep(password))
+ For short-term credentials ==> key = SASLprep(password)
+ */
+
+ tsk_sha1digest_t hmac;
+ const tnet_stun_attr_vdata_t *pc_attr_username = tsk_null, *pc_attr_realm = tsk_null, *pc_attr_nonce = tsk_null;
+ static const uint16_t kMsgIntTotalLength = kStunAttrHdrSizeInOctets + TSK_SHA1_DIGEST_SIZE;
+ _p_msg_int_start = p_buff_ptr;
+
+ // write attribute
+ if ((ret = tnet_stun_attr_write_with_padding(&pc_self->transac_id, pc_attr, p_buff_ptr, n_buff_size, &n_size))) {
+ return ret;
+ }
+ p_buff_ptr += n_size;
+ n_buff_size -= n_size;
+
+ // Length (must be correct before computing message integrity)
+ *((uint16_t*)&_p_buff_ptr[2]) = tnet_htons((unsigned short)((p_buff_ptr - _p_buff_ptr) - kStunPktHdrSizeInOctets));
+
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_username, (const tnet_stun_attr_t**)&pc_attr_username))) {
+ return ret;
+ }
+ if (pc_attr_username) {
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_realm, (const tnet_stun_attr_t**)&pc_attr_realm))) {
+ return ret;
+ }
+ if (pc_attr_realm) {
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_nonce, (const tnet_stun_attr_t**)&pc_attr_nonce))) {
+ return ret;
+ }
+ }
+ }
+ if (pc_attr_username && pc_attr_realm && pc_attr_nonce) {
+ // LONG-TERM
+ char* p_keystr = tsk_null;
+ tsk_md5digest_t md5;
+ tsk_sprintf(&p_keystr, "%s:%s:%s", pc_attr_username->p_data_ptr, pc_attr_realm->p_data_ptr, pc_self->p_pwd);
+ TSK_MD5_DIGEST_CALC(p_keystr, (tsk_size_t)tsk_strlen(p_keystr), md5);
+ hmac_sha1digest_compute(_p_buff_ptr, (tsk_size_t)(_p_msg_int_start - _p_buff_ptr), (const char*)md5, TSK_MD5_DIGEST_SIZE, hmac);
+ TSK_FREE(p_keystr);
+ }
+ else {
+ // SHORT-TERM
+ hmac_sha1digest_compute(_p_buff_ptr, (tsk_size_t)(_p_msg_int_start - _p_buff_ptr), pc_self->p_pwd, (tsk_size_t)tsk_strlen(pc_self->p_pwd), hmac);
+ }
+
+ // update MESSAGE-INTEGRITY attribute value
+ if ((ret = tnet_stun_attr_vdata_update((tnet_stun_attr_vdata_t*)pc_attr, hmac, TSK_SHA1_DIGEST_SIZE))) {
+ return ret;
+ }
+ if ((ret = tnet_stun_attr_write_with_padding(&pc_self->transac_id, pc_attr, _p_msg_int_start, kMsgIntTotalLength, &n_size))) {
+ return ret;
+ }
+ }
+
+ // Length before computing FINGERPRINT
+ *((uint16_t*)&_p_buff_ptr[2]) = tnet_htons((unsigned short)((p_buff_ptr - _p_buff_ptr) - kStunPktHdrSizeInOctets + ((pc_self->opt.fingerprint && (p_buff_ptr - _p_buff_ptr) >= 8) ? 8 : 0)));
+
+ if (pc_self->opt.fingerprint && (p_buff_ptr - _p_buff_ptr) >= 8) {
+ /* RFC 5389 - 15.5. FINGERPRINT
+ The FINGERPRINT attribute MAY be present in all STUN messages. The
+ value of the attribute is computed as the CRC-32 of the STUN message
+ up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with
+ the 32-bit value 0x5354554e
+ */
+ uint32_t u_fingerprint = tsk_pppfcs32(TSK_PPPINITFCS32, _p_buff_ptr, (int32_t)(p_buff_ptr - _p_buff_ptr)) ^ kStunFingerprintXorConst;
+ *((uint16_t*)&p_buff_ptr[0]) = tnet_htons(tnet_stun_attr_type_fingerprint); // Type
+ *((uint16_t*)&p_buff_ptr[2]) = tnet_htons(4); // Length
+ *((uint32_t*)&p_buff_ptr[4]) = (uint32_t)tnet_htonl(u_fingerprint);
+ p_buff_ptr += 8;
+ }
+
+ *p_written = (tsk_size_t)(p_buff_ptr - _p_buff_ptr);
+ return 0;
+}
+
+int tnet_stun_pkt_write_with_padding_2(const struct tnet_stun_pkt_s* pc_self, struct tsk_buffer_s** pp_buff)
+{
+ tsk_size_t u_buff_size;
+ int ret;
+ if (!pc_self || !pp_buff) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *pp_buff = tsk_null;
+ if ((ret = tnet_stun_pkt_get_size_in_octetunits_with_padding(pc_self, &u_buff_size))) {
+ goto bail;
+ }
+ u_buff_size += kStunBuffMinPad;
+ if (!(*pp_buff = tsk_buffer_create(tsk_null, u_buff_size))) {
+ goto bail;
+ }
+ if ((ret = tnet_stun_pkt_write_with_padding(pc_self, (*pp_buff)->data, (*pp_buff)->size, &(*pp_buff)->size))) {
+ goto bail;
+ }
+bail:
+ if (ret) {
+ TSK_OBJECT_SAFE_FREE(*pp_buff);
+ }
+ return ret;
+}
+
+int tnet_stun_pkt_is_complete(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t *pb_is_complete)
+{
+ if (!pb_is_complete) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *pb_is_complete = tsk_false;
+ if (pc_buff_ptr && n_buff_size >= kStunPktHdrSizeInOctets) {
+ tsk_size_t n_paylen_in_octets = tnet_ntohs_2(&pc_buff_ptr[2]);
+ *pb_is_complete = ((n_buff_size - kStunPktHdrSizeInOctets) >= n_paylen_in_octets);
+ }
+ return 0;
+}
+
+int tnet_stun_pkt_read(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tnet_stun_pkt_t** pp_pkt)
+{
+ tsk_bool_t b_is_complete;
+ uint16_t PayloadLengthInOctets;
+ tnet_stun_pkt_type_t Type;
+ tnet_stun_transac_id_t transac_id;
+ uint32_t MagicCookie;
+ int ret;
+
+ if (!pc_buff_ptr || !n_buff_size || !pp_pkt) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!TNET_STUN_BUFF_IS_STUN2(pc_buff_ptr, n_buff_size)) {
+ TSK_DEBUG_ERROR("Buffer doesn't contain a valid STUN2 pkt");
+ return -2;
+ }
+ if ((ret = tnet_stun_pkt_is_complete(pc_buff_ptr, n_buff_size, &b_is_complete))) {
+ return ret;
+ }
+ if (!b_is_complete) {
+ TSK_DEBUG_ERROR("Buffer too short(%u)", (unsigned)n_buff_size);
+ return -3;
+ }
+
+ // read the header
+ Type = tnet_ntohs_2(&pc_buff_ptr[0]);
+ PayloadLengthInOctets = tnet_ntohs_2(&pc_buff_ptr[2]);
+ MagicCookie = (uint32_t)tnet_ntohl_2(&pc_buff_ptr[4]);
+ if (MagicCookie != kStunMagicCookieLong) {
+ TSK_DEBUG_ERROR("%x not a valid STUN2 magic cookie", MagicCookie);
+ return -4;
+ }
+ memcpy(transac_id, &pc_buff_ptr[8], sizeof(tnet_stun_transac_id_t));
+ // create the pkt
+ if ((ret = tnet_stun_pkt_create(Type, PayloadLengthInOctets, (const tnet_stun_transac_id_t*)&transac_id, pp_pkt))) {
+ return ret;
+ }
+
+ if (PayloadLengthInOctets > 0) {
+ tnet_stun_attr_t* p_attr;
+ tsk_size_t n_consumed_octets;
+ pc_buff_ptr += kStunPktHdrSizeInOctets;
+ do {
+ if ((ret = tnet_stun_attr_read((const tnet_stun_transac_id_t*)&(*pp_pkt)->transac_id, pc_buff_ptr, PayloadLengthInOctets, &n_consumed_octets, &p_attr))) {
+ return ret;
+ }
+ if ((ret = tnet_stun_pkt_attr_add((*pp_pkt), &p_attr))) {
+ TSK_OBJECT_SAFE_FREE((*pp_pkt));
+ return ret;
+ }
+ PayloadLengthInOctets -= (uint16_t)n_consumed_octets;
+ pc_buff_ptr += n_consumed_octets;
+ } while (PayloadLengthInOctets >= kStunAttrHdrSizeInOctets);
+ }
+
+ return 0;
+}
+
+int tnet_stun_pkt_auth_prepare(tnet_stun_pkt_t* p_self, const char* pc_usr_name, const char* pc_pwd, const char* pc_realm, const char* pc_nonce)
+{
+ const tnet_stun_attr_t* pc_attr;
+ int ret;
+ static const tsk_sha1digest_t __pc_sha1digestEmpty = { 0 };
+ static const uint16_t __u_sha1digestEmpty = sizeof(__pc_sha1digestEmpty);
+ if (!p_self /*|| !pc_usr_name*/ || !pc_pwd /*|| !pc_realm || !pc_nonce*/) { // "username", "realm" and "nonce" are null for short-term authentication
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ // USERNAME
+ if (pc_usr_name) { // LONG-TERM, optional for SHORT-TERM
+ if ((ret = tnet_stun_pkt_attr_find_first(p_self, tnet_stun_attr_type_username, &pc_attr))) {
+ goto bail;
+ }
+ if (pc_attr) {
+ if ((ret = tnet_stun_attr_vdata_update((tnet_stun_attr_vdata_t*)pc_attr, (const uint8_t*)pc_usr_name, (uint16_t)tsk_strlen(pc_usr_name)))) {
+ goto bail;
+ }
+ }
+ else {
+ ret = tnet_stun_pkt_attrs_add(p_self,
+ TNET_STUN_PKT_ATTR_ADD_USERNAME_ZT(pc_usr_name),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ }
+ }
+ // REALM
+ if (pc_realm) { // LONG-TERM
+ if ((ret = tnet_stun_pkt_attr_find_first(p_self, tnet_stun_attr_type_realm, &pc_attr))) {
+ goto bail;
+ }
+ if (pc_attr) {
+ if ((ret = tnet_stun_attr_vdata_update((tnet_stun_attr_vdata_t*)pc_attr, (const uint8_t*)pc_realm, (uint16_t)tsk_strlen(pc_realm)))) {
+ goto bail;
+ }
+ }
+ else {
+ ret = tnet_stun_pkt_attrs_add(p_self,
+ TNET_STUN_PKT_ATTR_ADD_REALM_ZT(pc_realm),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ }
+ }
+ // NONCE
+ if (pc_nonce) { // LONG-TERM
+ if ((ret = tnet_stun_pkt_attr_find_first(p_self, tnet_stun_attr_type_nonce, &pc_attr))) {
+ goto bail;
+ }
+ if (pc_attr) {
+ if ((ret = tnet_stun_attr_vdata_update((tnet_stun_attr_vdata_t*)pc_attr, (const uint8_t*)pc_nonce, (uint16_t)tsk_strlen(pc_nonce)))) {
+ goto bail;
+ }
+ }
+ else {
+ ret = tnet_stun_pkt_attrs_add(p_self,
+ TNET_STUN_PKT_ATTR_ADD_NONCE_ZT(pc_nonce),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ }
+ }
+ // MESSAGE-INTEGRITY
+ if ((ret = tnet_stun_pkt_attr_find_first(p_self, tnet_stun_attr_type_message_integrity, &pc_attr))) {
+ goto bail;
+ }
+ if (!pc_attr) {
+ ret = tnet_stun_pkt_attrs_add(p_self,
+ TNET_STUN_PKT_ATTR_ADD_MESSAGE_INTEGRITY(__pc_sha1digestEmpty, __u_sha1digestEmpty),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ }
+
+ // PASSWORD
+ tsk_strupdate(&p_self->p_pwd, pc_pwd);
+
+bail:
+ return ret;
+}
+
+// pc_resp = 401 or 438
+int tnet_stun_pkt_auth_prepare_2(struct tnet_stun_pkt_s* p_self, const char* pc_usr_name, const char* pc_pwd, const struct tnet_stun_pkt_s* pc_resp)
+{
+ const tnet_stun_attr_vdata_t* pc_attr;
+ const char *pc_nonce, *pc_realm;
+ int ret;
+ if (!p_self || !pc_usr_name || !pc_pwd || !pc_resp) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // NONCE
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_resp, tnet_stun_attr_type_nonce, (const tnet_stun_attr_t**)&pc_attr))) {
+ goto bail;
+ }
+ if (!pc_attr || !pc_attr->p_data_ptr || !pc_attr->u_data_size) {
+ TSK_DEBUG_ERROR("Invalid NONCE in 401");
+ ret = -3;
+ goto bail;
+ }
+ pc_nonce = (const char*)pc_attr->p_data_ptr;
+ // REALM
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_resp, tnet_stun_attr_type_realm, (const tnet_stun_attr_t**)&pc_attr))) {
+ goto bail;
+ }
+ if (!pc_attr || !pc_attr->p_data_ptr || !pc_attr->u_data_size) {
+ TSK_DEBUG_ERROR("Invalid REALM in 401");
+ ret = -3;
+ goto bail;
+ }
+ pc_realm = (const char*)pc_attr->p_data_ptr;
+
+ if ((ret = tnet_stun_pkt_auth_prepare(p_self, pc_usr_name, pc_pwd, pc_realm, pc_nonce))) {
+ goto bail;
+ }
+
+ // TRANSACTION-ID
+ if ((ret = tnet_stun_utils_transac_id_rand(&p_self->transac_id))) {
+ goto bail;
+ }
+
+bail:
+ return ret;
+}
+
+int tnet_stun_pkt_auth_copy(tnet_stun_pkt_t* p_self, const char* pc_usr_name, const char* pc_pwd, const tnet_stun_pkt_t* pc_pkt)
+{
+ const tnet_stun_attr_vdata_t *pc_attr_realm = tsk_null, *pc_attr_nonce = tsk_null;
+ int ret;
+ tsk_bool_t b_ok;
+ if (!p_self || !pc_pwd || !pc_usr_name || !pc_pkt) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ b_ok =
+ (ret = tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_realm, (const tnet_stun_attr_t**)&pc_attr_realm)) == 0 && pc_attr_realm
+ && (ret = tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_nonce, (const tnet_stun_attr_t**)&pc_attr_nonce)) == 0 && pc_attr_nonce;
+
+ if (b_ok && (ret = tnet_stun_pkt_auth_prepare(p_self, pc_usr_name, pc_pwd, (const char*)pc_attr_realm->p_data_ptr, (const char*)pc_attr_nonce->p_data_ptr))) {
+ goto bail;
+ }
+
+bail:
+ return ret;
+}
+
+int tnet_stun_pkt_get_errorcode(const struct tnet_stun_pkt_s* pc_self, uint16_t* pu_code)
+{
+ const tnet_stun_attr_error_code_t* pc_attr;
+ int ret;
+ if (!pc_self && !pu_code) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *pu_code = 0;
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_error_code, (const tnet_stun_attr_t**)&pc_attr))) {
+ return ret;
+ }
+ if (pc_attr) {
+ *pu_code = (pc_attr->u_class * 100) + pc_attr->u_number;
+ }
+ return 0;
+}
+
+int tnet_stun_pkt_process_err420(struct tnet_stun_pkt_s *p_self, const struct tnet_stun_pkt_s *pc_pkt_resp420)
+{
+ const tnet_stun_attr_vdata_t* pc_attr;
+ uint16_t u16;
+ int ret;
+ tsk_bool_t b_done = tsk_false;
+ if (!p_self || !pc_pkt_resp420) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_pkt_resp420, tnet_stun_attr_type_unknown_attrs, (const tnet_stun_attr_t**)&pc_attr))) {
+ goto bail;
+ }
+ if (!pc_attr || !pc_attr->p_data_ptr || (pc_attr->u_data_size & 1)) {
+ TSK_DEBUG_ERROR("UNKNOWN-ATTRIBUTES missing in 420");
+ ret = -3;
+ goto bail;
+ }
+ for (u16 = 0; u16 < pc_attr->u_data_size; u16 += 2) {
+ switch (*((uint16_t*)&pc_attr->p_data_ptr[u16])) {
+ case tnet_stun_attr_type_dont_fragment: {
+ p_self->opt.dontfrag = 0;
+ b_done = tsk_true;
+ break;
+ }
+ case tnet_stun_attr_type_fingerprint: {
+ p_self->opt.fingerprint = 0;
+ b_done = tsk_true;
+ break;
+ }
+ }
+ }
+
+ if (b_done) {
+ // TRANSACTION-ID
+ if ((ret = tnet_stun_utils_transac_id_rand(&p_self->transac_id))) {
+ goto bail;
+ }
+ }
+
+bail:
+ return ret;
+}
+
+static tsk_object_t* tnet_stun_pkt_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_stun_pkt_t *p_pkt = (tnet_stun_pkt_t *)self;
+ if (p_pkt) {
+ p_pkt->opt.fingerprint = kStunOptFingerPrint;
+ p_pkt->opt.dontfrag = kStunOptDontFragment;
+ }
+ return self;
+}
+static tsk_object_t* tnet_stun_pkt_dtor(tsk_object_t * self)
+{
+ tnet_stun_pkt_t *p_pkt = (tnet_stun_pkt_t *)self;
+ if (p_pkt) {
+#if PRINT_DESTROYED_MSG
+ TSK_DEBUG_INFO("*** STUN pkt destroyed ***");
+#endif
+ TSK_OBJECT_SAFE_FREE(p_pkt->p_list_attrs);
+ TSK_FREE(p_pkt->p_pwd);
+ }
+ return self;
+}
+static const tsk_object_def_t tnet_stun_pkt_def_s = {
+ sizeof(tnet_stun_pkt_t),
+ tnet_stun_pkt_ctor,
+ tnet_stun_pkt_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_stun_pkt_def_t = &tnet_stun_pkt_def_s;
diff --git a/tinyNET/src/stun/tnet_stun_pkt.h b/tinyNET/src/stun/tnet_stun_pkt.h
new file mode 100644
index 0000000..da27673
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_pkt.h
@@ -0,0 +1,187 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_STUN_PKT_H
+#define TNET_STUN_PKT_H
+
+#include "tinynet_config.h"
+#include "stun/tnet_stun_attr.h"
+
+#include "tsk_object.h"
+#include "tsk_list.h"
+#include "tsk_buffer.h"
+
+TNET_BEGIN_DECLS
+
+
+/**@ingroup tnet_stun_group
+* @def TNET_STUN_PKT_IS_REQ
+* Checks whether the STUN message is a request or not.
+*/
+/**@ingroup tnet_stun_group
+* @def TNET_STUN_PKT_IS_INDICATION
+* Checks whether the STUN message is an indicaton message or not.
+*/
+/**@ingroup tnet_stun_group
+* @def TNET_STUN_RESP_IS_SUCCESS
+* Checks whether the STUN message is a success response or not.
+*/
+/**@ingroup tnet_stun_group
+* @def TNET_STUN_RESP_IS_ERROR
+* Checks whether the STUN message is an error response or not.
+*/
+#define TNET_STUN_PKT_IS_REQ(p_self) ((p_self) && (((p_self)->e_type & 0x0110) == tnet_stun_mask_request))
+#define TNET_STUN_PKT_IS_RESP(p_self) (TNET_STUN_PKT_RESP_IS_SUCCESS((p_self)) || TNET_STUN_PKT_RESP_IS_ERROR((p_self)))
+#define TNET_STUN_PKT_IS_INDICATION(p_self) ((p_self) && (((p_self)->e_type & 0x0110) == tnet_stun_mask_indication))
+#define TNET_STUN_PKT_RESP_IS_SUCCESS(p_self) ((p_self) && (((p_self)->e_type & 0x0110) == tnet_stun_mask_success))
+#define TNET_STUN_PKT_RESP_IS_ERROR(p_self) ((p_self) && (((p_self)->e_type & 0x0110) == tnet_stun_mask_error))
+
+typedef enum tnet_stun_pkt_attr_add_e {
+ tnet_stun_pkt_attr_add_null = 0,
+ tnet_stun_pkt_attr_add_none = tnet_stun_pkt_attr_add_null,
+ tnet_stun_pkt_attr_add_vdata,
+ tnet_stun_pkt_attr_add_address,
+ tnet_stun_pkt_attr_add_error_code,
+ tnet_stun_pkt_attr_add_unknown_attrs,
+ tnet_stun_pkt_attr_add_unknown_attrs_val,
+}
+tnet_stun_pkt_attr_add_t;
+
+#define TNET_STUN_PKT_ATTR_ADD_NULL() tnet_stun_pkt_attr_add_null
+#define TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, P_DATA_PTR, U_DATA_SIZE) tnet_stun_pkt_attr_add_vdata, (enum tnet_stun_attr_type_e)(E_TYPE), (const uint8_t*)(P_DATA_PTR), (uint16_t)(U_DATA_SIZE)
+#define TNET_STUN_PKT_ATTR_ADD_UINT0(E_TYPE) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, tsk_null, 0)
+#define TNET_STUN_PKT_ATTR_ADD_UINT8(E_TYPE, U8) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, &U8, 1)
+#define TNET_STUN_PKT_ATTR_ADD_UINT16(E_TYPE, U16) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, &U16, 2)
+#define TNET_STUN_PKT_ATTR_ADD_UINT32(E_TYPE, U32) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, &U32, 4)
+#define TNET_STUN_PKT_ATTR_ADD_UINT64(E_TYPE, U64) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, &U64, 8)
+#define TNET_STUN_PKT_ATTR_ADD_STR(E_TYPE, PC_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, PC_STR, tsk_strlen(PC_STR))
+#define TNET_STUN_PKT_ATTR_ADD_ADDRESS(E_TYPE, E_FAMILY, U_PORT, PC_ADDR_PTR) tnet_stun_pkt_attr_add_address, (enum tnet_stun_attr_type_e)(E_TYPE), (enum tnet_stun_address_family_e)(E_FAMILY), (uint16_t)(U_PORT), (const tnet_stun_addr_t*)PC_ADDR_PTR
+#define TNET_STUN_PKT_ATTR_ADD_ADDRESS_V4(E_TYPE, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS((E_TYPE), tnet_stun_address_family_ipv4, (U_PORT), (PC_ADDR_PTR))
+#define TNET_STUN_PKT_ATTR_ADD_ADDRESS_V6(E_TYPE, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS((E_TYPE), tnet_stun_address_family_ipv6, (U_PORT), (PC_ADDR_PTR))
+// rfc5389 - 15.1. MAPPED-ADDRESS
+#define TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS(E_FAMILY, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS(tnet_stun_attr_type_mapped_address, (E_FAMILY), (U_PORT), (PC_ADDR_PTR))
+#define TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS_V4(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS(tnet_stun_address_family_ipv4, (U_PORT), (PC_ADDR_PTR))
+#define TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS_V6(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS(tnet_stun_address_family_ipv6, (U_PORT), (PC_ADDR_PTR))
+// rfc5389 - 15.2. XOR-MAPPED-ADDRESS
+#define TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS(E_FAMILY, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS(tnet_stun_attr_type_xor_mapped_address, (E_FAMILY), (U_PORT), (PC_ADDR_PTR))
+#define TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS_V4(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS(tnet_stun_address_family_ipv4, (U_PORT), (PC_ADDR_PTR))
+#define TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS_V6(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS(tnet_stun_address_family_ipv6, (U_PORT), (PC_ADDR_PTR))
+// rfc5389 - 15.3. USERNAME
+#define TNET_STUN_PKT_ATTR_ADD_USERNAME(PC_USERNAME_STR, U_USERNAME_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_username, (PC_USERNAME_STR), (U_USERNAME_STR))
+#define TNET_STUN_PKT_ATTR_ADD_USERNAME_ZT(PC_USERNAME_STR) TNET_STUN_PKT_ATTR_ADD_USERNAME(PC_USERNAME_STR, tsk_strlen(PC_USERNAME_STR))
+// rfc5389 - 15.4. MESSAGE-INTEGRITY
+#define TNET_STUN_PKT_ATTR_ADD_MESSAGE_INTEGRITY(PC_SHA1_STR, U_SHA1_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_message_integrity, (PC_SHA1_STR), (U_SHA1_STR))
+#define TNET_STUN_PKT_ATTR_ADD_MESSAGE_INTEGRITY_ZT(PC_SHA1_STR) TNET_STUN_PKT_ATTR_ADD_MESSAGE_INTEGRITY(PC_SHA1_STR, tsk_strlen(PC_SHA1_STR))
+// rfc5389 - 15.5. FINGERPRINT
+#define TNET_STUN_PKT_ATTR_ADD_FINGERPRINT(U32_CRC32) TNET_STUN_PKT_ATTR_ADD_UINT32(tnet_stun_attr_type_fingerprint, U32_CRC32)
+// rfc5389 - 15.6. ERROR-CODE
+#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(U8_CLASS, U8_NUMBER, PC_REASON_STR) tnet_stun_pkt_attr_add_error_code, (uint8_t)(U8_CLASS), (uint8_t)(U8_NUMBER), (const char*)(PC_REASON_STR)
+#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_TRY_ALTERNATE() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassTryAlternate, kStunErrorNumberTryAlternate, kStunErrorPhraseTryAlternate)
+#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_BAD_REQUEST() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassBadRequest, kStunErrorNumberBadRequest, kStunErrorPhraseBadRequest)
+#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_UNAUTHORIZED() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassUnauthorized, kStunErrorNumberUnauthorized, kStunErrorPhraseUnauthorized)
+#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_UNKNOWN_ATTRIBUTE() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassUnknownAttribute, kStunErrorNumberUnknownAttribute, kStunErrorPhraseUnknownAttribute)
+#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_STALE_NONCE() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassStaleNonce, kStunErrorNumberStaleNonce, kStunErrorPhraseStaleNonce)
+#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_SERVER_ERROR() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassServerError, kStunErrorNumberServerError, kStunErrorPhraseServerError)
+// rfc5389 - 15.7. REALM
+#define TNET_STUN_PKT_ATTR_ADD_REALM(PC_REALM_STR, U_REALM_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_realm, (PC_REALM_STR), (U_REALM_STR))
+#define TNET_STUN_PKT_ATTR_ADD_REALM_ZT(PC_REALM_STR) TNET_STUN_PKT_ATTR_ADD_REALM(PC_REALM_STR, tsk_strlen(PC_REALM_STR))
+// rfc5389 - 15.8. NONCE
+#define TNET_STUN_PKT_ATTR_ADD_NONCE(PC_NONCE_STR, U_NONCE_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_nonce, (PC_NONCE_STR), (U_NONCE_STR))
+#define TNET_STUN_PKT_ATTR_ADD_NONCE_ZT(PC_NONCE_STR) TNET_STUN_PKT_ATTR_ADD_NONCE(PC_NONCE_STR, tsk_strlen(PC_NONCE_STR))
+// rfc5389 - 15.9. UNKNOWN-ATTRIBUTES
+#define TNET_STUN_PKT_ATTR_ADD_UNKNOWN_ATTRS(...) tnet_stun_pkt_attr_add_unknown_attrs, ##__VA_ARGS__
+#define TNET_STUN_PKT_ATTR_ADD_UNKNOWN_ATTRS_VAL(U16_VAL) tnet_stun_pkt_attr_add_unknown_attrs_val, (uint16_t)U16_VAL
+// rfc5389 - 15.10. SOFTWARE
+#define TNET_STUN_PKT_ATTR_ADD_SOFTWARE(PC_SOFTWARE_STR, U_SOFTWARE_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_software, (PC_SOFTWARE_STR), (U_SOFTWARE_STR))
+#define TNET_STUN_PKT_ATTR_ADD_SOFTWARE_ZT(PC_SOFTWARE_STR) TNET_STUN_PKT_ATTR_ADD_SOFTWARE(PC_SOFTWARE_STR, tsk_strlen(PC_SOFTWARE_STR))
+// rfc5389 - 15.11. ALTERNATE-SERVER
+#define TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER(E_FAMILY, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS(tnet_stun_attr_type_alternate_server, (E_FAMILY), (U_PORT), (PC_ADDR_PTR))
+#define TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER_V4(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER(tnet_stun_address_family_ipv4, (U_PORT), (PC_ADDR_PTR))
+#define TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER_V6(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER(tnet_stun_address_family_ipv6, (U_PORT), (PC_ADDR_PTR))
+
+// rfc5766(TURN) - 14.1. CHANNEL-NUMBER
+#define TNET_STUN_PKT_ATTR_ADD_CHANNEL_NUMBER(U16_CHANNEL_NUMBER) TNET_STUN_PKT_ATTR_ADD_UINT16(tnet_stun_attr_type_channel_number, U16_CHANNEL_NUMBER)
+// rfc5766(TURN) - 14.2. LIFETIME
+#define TNET_STUN_PKT_ATTR_ADD_LIFETIME(U32_LIFETIME) TNET_STUN_PKT_ATTR_ADD_UINT32(tnet_stun_attr_type_lifetime, U32_LIFETIME)
+// rfc5766(TURN) - 14.3. XOR-PEER-ADDRESS
+#define TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(E_FAMILY, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS(tnet_stun_attr_type_xor_peer_address, (E_FAMILY), (U_PORT), (PC_ADDR_PTR))
+#define TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS_V4(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(tnet_stun_address_family_ipv4, (U_PORT), (PC_ADDR_PTR))
+#define TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS_V6(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(tnet_stun_address_family_ipv6, (U_PORT), (PC_ADDR_PTR))
+// rfc5766(TURN) - 14.4. DATA
+#define TNET_STUN_PKT_ATTR_ADD_DATA(PC_DATA_PTR, U_DATA_SIZE) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_data, (PC_DATA_PTR), (U_DATA_SIZE))
+// rfc5766(TURN) - 14.7. REQUESTED-TRANSPORT
+#define TNET_STUN_PKT_ATTR_ADD_REQUESTED_TRANSPORT(U8_PROTOCOL) TNET_STUN_PKT_ATTR_ADD_UINT8(tnet_stun_attr_type_requested_transport, U8_PROTOCOL)
+// rfc5766(TURN) - 14.8. DONT-FRAGMENT
+#define TNET_STUN_PKT_ATTR_ADD_DONT_FRAGMENT() TNET_STUN_PKT_ATTR_ADD_UINT0(tnet_stun_attr_type_dont_fragment)
+
+// rfc5245(ICE) - 19.1. New Attributes (PRIORITY)
+#define TNET_STUN_PKT_ATTR_ADD_ICE_PRIORITY(U32_PRIORITY) TNET_STUN_PKT_ATTR_ADD_UINT32(tnet_stun_attr_type_ice_priority, U32_PRIORITY)
+// rfc5245(ICE) - 19.1. New Attributes (USE-CANDIDATE)
+#define TNET_STUN_PKT_ATTR_ADD_ICE_USE_CANDIDATE() TNET_STUN_PKT_ATTR_ADD_UINT0(tnet_stun_attr_type_ice_use_candidate)
+// rfc5245(ICE) - 19.1. New Attributes (ICE-CONTROLLED)
+#define TNET_STUN_PKT_ATTR_ADD_ICE_CONTROLLED(U64_CONTROLLED) TNET_STUN_PKT_ATTR_ADD_UINT64(tnet_stun_attr_type_ice_controlled, U64_CONTROLLED)
+// rfc5245(ICE) - 19.1. New Attributes (ICE-CONTROLLED)
+#define TNET_STUN_PKT_ATTR_ADD_ICE_CONTROLLING(U64_CONTROLLING) TNET_STUN_PKT_ATTR_ADD_UINT64(tnet_stun_attr_type_ice_controlling, U64_CONTROLLING)
+
+// rfc6062 - 6.2. New STUN Attributes (CONNECTION-ID)
+#define TNET_STUN_PKT_ATTR_ADD_CONNECTION_ID(U32_CONNECTION_ID) TNET_STUN_PKT_ATTR_ADD_UINT32(tnet_stun_attr_type_connection_id, U32_CONNECTION_ID)
+
+typedef struct tnet_stun_pkt_s {
+ TSK_DECLARE_OBJECT;
+ enum tnet_stun_pkt_type_e e_type;
+ uint16_t u_length; // 16bits: contain the size, in bytes, of the message not including the 20-byte STUN header
+ tnet_stun_transac_id_t transac_id; // 96bits : always in network byte-order
+ tnet_stun_attrs_L_t* p_list_attrs;
+ struct {
+ unsigned fingerprint:1;
+ unsigned dontfrag:1;
+ } opt;
+ char *p_pwd;
+} tnet_stun_pkt_t;
+#define TNET_STUN_DECLARE_PKT struct tnet_stun_pkt_s __base__
+#define TNET_STUN_PKT(p_self) ((struct tnet_stun_pkt_s*)(p_self))
+typedef tsk_list_t tnet_stun_pkts_L_t;
+typedef tnet_stun_pkt_t tnet_stun_pkt_req_t;
+typedef tnet_stun_pkt_t tnet_stun_pkt_resp_t;
+
+TINYNET_API int tnet_stun_pkt_create(enum tnet_stun_pkt_type_e e_type, uint16_t u_length, const tnet_stun_transac_id_t* pc_transac_id, struct tnet_stun_pkt_s** pp_attr);
+#define tnet_stun_pkt_create_empty(e_type, pp_attr) tnet_stun_pkt_create((e_type), 0, tsk_null, (pp_attr))
+TINYNET_API int tnet_stun_pkt_attr_add(struct tnet_stun_pkt_s* p_self, struct tnet_stun_attr_s** pp_attr);
+TINYNET_API int tnet_stun_pkt_attrs_add(struct tnet_stun_pkt_s* p_self, ...);
+TINYNET_API int tnet_stun_pkt_attr_remove(struct tnet_stun_pkt_s* p_self, enum tnet_stun_attr_type_e e_type);
+TINYNET_API int tnet_stun_pkt_attr_find(const struct tnet_stun_pkt_s* pc_self, enum tnet_stun_attr_type_e e_type, tsk_size_t u_index, const struct tnet_stun_attr_s** ppc_attr);
+#define tnet_stun_pkt_attr_find_first(pc_self, e_type, ppc_attr) tnet_stun_pkt_attr_find((pc_self), (e_type), 0, (ppc_attr))
+TINYNET_API tsk_bool_t tnet_stun_pkt_attr_exists(const struct tnet_stun_pkt_s* pc_self, enum tnet_stun_attr_type_e e_type);
+TINYNET_API int tnet_stun_pkt_get_size_in_octetunits_without_padding(const struct tnet_stun_pkt_s* pc_self, tsk_size_t* p_size);
+TINYNET_API int tnet_stun_pkt_get_size_in_octetunits_with_padding(const struct tnet_stun_pkt_s* pc_self, tsk_size_t* p_size);
+TINYNET_API int tnet_stun_pkt_write_with_padding(const struct tnet_stun_pkt_s* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written);
+TINYNET_API int tnet_stun_pkt_write_with_padding_2(const struct tnet_stun_pkt_s* pc_self, struct tsk_buffer_s** pp_buff);
+TINYNET_API int tnet_stun_pkt_is_complete(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t *pb_is_complete);
+TINYNET_API int tnet_stun_pkt_read(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, struct tnet_stun_pkt_s** pp_pkt);
+TINYNET_API int tnet_stun_pkt_auth_prepare(struct tnet_stun_pkt_s* p_self, const char* pc_usr_name, const char* pc_pwd, const char* pc_realm, const char* pc_nonce);
+#define tnet_stun_pkt_auth_prepare_longterm(p_self, pc_usr_name, pc_pwd, pc_realm, pc_nonce) tnet_stun_pkt_auth_prepare((p_self), (pc_usr_name), (pc_pwd), (pc_realm), (pc_nonce))
+#define tnet_stun_pkt_auth_prepare_shortterm(p_self, pc_usr_name, pc_pwd) tnet_stun_pkt_auth_prepare((p_self), (pc_usr_name), (pc_pwd), tsk_null, tsk_null)
+#define tnet_stun_pkt_auth_prepare_shortterm_2(p_self, pc_pwd) tnet_stun_pkt_auth_prepare_shortterm((p_self), tsk_null, (pc_pwd))
+TINYNET_API int tnet_stun_pkt_auth_prepare_2(struct tnet_stun_pkt_s* p_self, const char* pc_usr_name, const char* pc_pwd, const struct tnet_stun_pkt_s* pc_resp);
+TINYNET_API int tnet_stun_pkt_auth_copy(struct tnet_stun_pkt_s* p_self, const char* pc_usr_name, const char* pc_pwd, const struct tnet_stun_pkt_s* pc_pkt);
+TINYNET_API int tnet_stun_pkt_get_errorcode(const struct tnet_stun_pkt_s* pc_self, uint16_t* pu_code);
+TINYNET_API int tnet_stun_pkt_process_err420(struct tnet_stun_pkt_s *p_self, const struct tnet_stun_pkt_s *pc_pkt_resp420);
+
+TNET_END_DECLS
+
+#endif /* TNET_STUN_PKT_H */
diff --git a/tinyNET/src/stun/tnet_stun_types.h b/tinyNET/src/stun/tnet_stun_types.h
new file mode 100644
index 0000000..386f471
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_types.h
@@ -0,0 +1,373 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_STUN_TYPES_H
+#define TNET_STUN_TYPES_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+typedef uint8_t tnet_stun_addr_t[16]; // IPv4(32bits) or IPv6(128bits)
+typedef uint64_t tnet_stun_binding_id_t;
+typedef long tnet_turn_peer_id_t;
+
+/**@ingroup tnet_stun_group
+ * Checks if the pointer to the buffer hold a STUN header by checking that it starts with 0b00 and contain the magic cookie.
+ * As per RFC 5389 subclause 19: Explicitly point out that the most significant 2 bits of STUN are
+ * 0b00, allowing easy differentiation with RTP packets when used with ICE.
+ * As per RFC 5389 subclause 6: The magic cookie field MUST contain the fixed value 0x2112A442 in
+ * network byte order.
+ *
+ * @param PU8 The pointer to the buffer holding the STUN raw data.
+**/
+#define TNET_STUN_BUFF_IS_STUN2(PU8, SIZE) \
+ ( \
+ ((PU8)) && \
+ ((SIZE) >= kStunPktHdrSizeInOctets) && \
+ (((PU8)[0] & 0xc0) == 0x00) && \
+ ( PU8[4] == 0x21 && PU8[5] == 0x12 && PU8[6] == 0xA4 && PU8[7] == 0x42 ) \
+ )
+
+// rfc5766 - 11. Channels
+#define TNET_STUN_BUFF_IS_CHANNEL_DATA(PU8, SIZE) \
+ ( \
+ ((PU8)) && \
+ ((SIZE) >= kStunChannelDataHdrSizeInOctets) && \
+ (((PU8)[0] & 0xc0) == 0x40) \
+ )
+
+#define kStunOptFingerPrint 1
+#define kStunOptDontFragment 1
+
+#define kStunErrCodeUnauthorized 401
+#define kStunErrCodeUnknownAttributes 420
+#define kStunErrCodeStaleNonce 438
+#define kStunErrCodeIceConflict 487
+
+// Estimate of the round-trip time (RTT) in millisecond.
+#define kStunRTO 500
+
+// Number of retransmission for UDP retransmission in millisecond.
+// 7.2.1. Sending over UDP
+// Rc SHOULD be configurable and SHOULD have a default of 7.
+#define kStunRC /*7*/4/* 7 is too hight */
+
+#define kStunBindingInvalidId 0
+
+#if !defined(kStunBuffMinPad)
+# define kStunBuffMinPad 40 // to make the buffer kasher
+#endif /* kStunBuffMinPad */
+
+#if !defined(kStunSoftware)
+# define kStunSoftware TNET_SOFTWARE
+#endif /* kStunSoftware */
+
+#if !defined(kStunPortDefaultTcpUdp)
+# define kStunPortDefaultTcpUdp 3478
+#endif /* kStunPortDefaultTcpUdp */
+
+#if !defined(kStunPortDefaultTls)
+# define kStunPortDefaultTls 5349
+#endif /* kStunPortDefaultTls */
+
+// rfc5389 - 15. STUN Attributes
+#if !defined(kStunAttrHdrSizeInOctets)
+# define kStunAttrHdrSizeInOctets 4
+#endif /* kStunAttrHdrSizeInOctets */
+
+// rfc5389 - 6. STUN Message Structure
+#if !defined(kStunPktHdrSizeInOctets)
+# define kStunPktHdrSizeInOctets 20
+#endif /* kStunPktHdrSizeInOctets */
+
+// STUN2 magic cookie value in network byte order as per RFC 5389 subclause 6.
+#if !defined(kStunMagicCookieLong)
+# define kStunMagicCookieLong 0x2112A442
+#endif /* kStunMagicCookieLong */
+#if !defined(kStunMagicCookie)
+# define kStunMagicCookie kStunMagicCookieLong
+#endif /* kStunMagicCookie */
+#if !defined(kStunMagicCookieShort)
+# define kStunMagicCookieShort 0x2112
+#endif /* kStunMagicCookieShort */
+
+#if !defined (kStunFingerprintXorConst)
+# define kStunFingerprintXorConst 0x5354554e
+#endif /* kStunFingerprintXorConst */
+
+// STUN trasactionn ID size (96bits = 12bytes)
+#if !defined(kStunTransacIdSize)
+# define kStunTransacIdSize 12
+#endif
+typedef uint8_t tnet_stun_transac_id_t[kStunTransacIdSize];
+
+/**@ingroup tnet_stun_group
+ * List of all supported STUN classes as per RFC 5389 subcaluse 6.
+**/
+typedef enum tnet_stun_class_e {
+ tnet_stun_class_request = 0x00, /**< Request class: 0b00 */
+ tnet_stun_class_indication = 0x01, /**< Indication class: 0b01 */
+ tnet_stun_class_success_response = 0x02, /**< Success response class: 0b10 */
+ tnet_stun_class_error_response = 0x03, /**< Error/failure response class: 0b11 */
+}
+tnet_stun_class_t;
+
+/**@ingroup tnet_stun_group
+ * List of all supported STUN methods.
+ * RFC 5389 defines only one method(Bining). All other methods have been defined by TURN (rfc5766 section 13).
+**/
+typedef enum tnet_stun_method_e {
+ tnet_stun_method_binding = 0x0001, /**< RFC 5389 - Binding method: 0b000000000001 */
+
+ tnet_stun_method_allocate = 0x0003, /**< rfc5766 - Allocate (only request/response semantics defined) */
+ tnet_stun_method_refresh = 0x0004, /**< rfc5766 - Refresh (only request/response semantics defined) */
+ tnet_stun_method_send = 0x0006, /**< rfc5766 - Send (only indication semantics defined) */
+ tnet_stun_method_data = 0x0007, /**< rfc5766 - Data (only indication semantics defined) */
+ tnet_stun_method_createpermission = 0x0008, /**< rfc5766 - CreatePermission (only request/response semantics defined */
+ tnet_stun_method_channelbind = 0x0009, /**< rfc5766 - ChannelBind (only request/response semantics defined) */
+ tnet_stun_method_connect = 0x000a,/**< rfc6062 - Connect */
+ tnet_stun_method_connectionbind = 0x000b,/**< rfc6062 - ConnectionBind */
+ tnet_stun_method_connectionattempt = 0x000c,/**< rfc6062 - ConnectionAttempt */
+}
+tnet_stun_method_t;
+
+/**@ingroup tnet_stun_group
+*/
+typedef enum tnet_stun_mask_e {
+ tnet_stun_mask_request = 0x0000,
+ tnet_stun_mask_indication = 0x0010,
+ tnet_stun_mask_success = 0x0100,
+ tnet_stun_mask_error = 0x0110
+}
+tnet_stun_mask_t;
+
+/**@ingroup tnet_stun_group
+ * STUN IP family as per RFC 5389 subclause 15.1.
+**/
+typedef enum tnet_stun_address_family_e {
+ tnet_stun_address_family_ipv4 = 0x01,
+ tnet_stun_address_family_ipv6 = 0x02
+} tnet_stun_address_family_t;
+
+// rfc5766 - 14.7. REQUESTED-TRANSPORT
+typedef enum tnet_turn_transport_e {
+ tnet_turn_transport_udp = 17,
+ tnet_turn_transport_tcp = 6
+}
+tnet_turn_transport_t;
+
+// RFC 5389 - 15.6. ERROR-CODE
+#define kStunErrorClassTryAlternate 3
+#define kStunErrorNumberTryAlternate 0
+#define kStunErrorPhraseTryAlternate "Try Alternate"
+#define kStunErrorClassBadRequest 4
+#define kStunErrorNumberBadRequest 0
+#define kStunErrorPhraseBadRequest "Bad Request"
+#define kStunErrorClassUnauthorized 4
+#define kStunErrorNumberUnauthorized 1
+#define kStunErrorPhraseUnauthorized "Unauthorized"
+#define kStunErrorClassUnknownAttribute 4
+#define kStunErrorNumberUnknownAttribute 20
+#define kStunErrorPhraseUnknownAttribute "Unknown Attribute"
+#define kStunErrorClassStaleNonce 4
+#define kStunErrorNumberStaleNonce 38
+#define kStunErrorPhraseStaleNonce "Stale Nonce"
+#define kStunErrorClassServerError 5
+#define kStunErrorNumberServerError 0
+#define kStunErrorPhraseServerError "Server Error"
+// rfc5766 - 15. New STUN Error Response Codes
+#define kStunErrorClassForbidden 4
+#define kStunErrorNumberForbidden 3
+#define kStunErrorPhraseForbidden "Forbidden"
+#define kStunErrorClassAllocationMismatch 4
+#define kStunErrorNumberAllocationMismatch 37
+#define kStunErrorPhraseAllocationMismatch "Allocation Mismatch"
+#define kStunErrorClassWrongCredentials 4
+#define kStunErrorNumberWrongCredentials 42
+#define kStunErrorPhraseWrongCredentials "Wrong Credentials"
+#define kStunErrorClassUnsupportedTransportProtocol 4
+#define kStunErrorNumberUnsupportedTransportProtocol 42
+#define kStunErrorPhraseUnsupportedTransportProtocol "Unsupported Transport Protocol"
+#define kStunErrorClassAllocationQuotaReached 4
+#define kStunErrorNumberAllocationQuotaReached 86
+#define kStunErrorPhraseAllocationQuotaReached "Allocation Quota Reached"
+#define kStunErrorClassInsufficientCapacity 5
+#define kStunErrorNumberInsufficientCapacity 8
+#define kStunErrorPhraseInsufficientCapacity "Insufficient Capacity"
+
+
+/**@ingroup tnet_stun_group
+ * STUN attr types as per RFC 5389 subclause 18.2.
+**/
+typedef enum tnet_stun_attr_type_e {
+ /* === RFC 5389 - Comprehension-required range (0x0000-0x7FFF) */
+ tnet_stun_attr_type_reserved = 0x0000, /**< (Reserved) */
+ tnet_stun_attr_type_mapped_address = 0x0001, /**< http://tools.ietf.org/html/rfc5389#page-32 */
+ tnet_stun_attr_type_response_address = 0x0002, /**< (Reserved; was RESPONSE-ADDRESS) */
+ tnet_stun_attr_type_change_address = 0x0003, /**< (Reserved; was CHANGE-ADDRESS) */
+ tnet_stun_attr_type_source_address = 0x0004, /**< (Reserved; was SOURCE-ADDRESS) */
+ tnet_stun_attr_type_changed_address = 0x0005, /**< (Reserved; was CHANGED-ADDRESS) */
+ tnet_stun_attr_type_username = 0x0006, /**< http://tools.ietf.org/html/rfc5389#page-34 */
+ tnet_stun_attr_type_password = 0x0007, /**< (Reserved; was PASSWORD) */
+ tnet_stun_attr_type_message_integrity = 0x0008, /**< http://tools.ietf.org/html/rfc5389#page-34 */
+ tnet_stun_attr_type_error_code = 0x0009, /**< http://tools.ietf.org/html/rfc5389#page-36 */
+ tnet_stun_attr_type_unknown_attrs = 0x000A, /**< http://tools.ietf.org/html/rfc5389#page-38 */
+ tnet_stun_attr_type_reflected_from = 0x000B, /**< (Reserved; was REFLECTED-FROM) */
+ tnet_stun_attr_type_realm = 0x0014, /**< http://tools.ietf.org/html/rfc5389#page-38 */
+ tnet_stun_attr_type_nonce = 0x0015, /**< http://tools.ietf.org/html/rfc5389#page-38 */
+ tnet_stun_attr_type_xor_mapped_address = 0x0020, /**< http://tools.ietf.org/html/rfc5389#page-33 */
+
+ /* === RFC 5389 - Comprehension-optional range (0x8000-0xFFFF) */
+ tnet_stun_attr_type_software = 0x8022, /**< http://tools.ietf.org/html/rfc5389#page-39 */
+ tnet_stun_attr_type_alternate_server = 0x8023, /**< http://tools.ietf.org/html/rfc5389#page-39 */
+ tnet_stun_attr_type_fingerprint = 0x8028, /**< http://tools.ietf.org/html/rfc5389#page-36 */
+
+ /* === rfc5766 */
+ tnet_stun_attr_type_channel_number = 0x000C, /**< rfc5766 - CHANNEL-NUMBER */
+ tnet_stun_attr_type_lifetime = 0x000D, /**< rfc5766 - LIFETIME */
+ tnet_stun_attr_type_reserved2 = 0x0010, /**< rfc5766 - Reserved (was BANDWIDTH) */
+ tnet_stun_attr_type_xor_peer_address = 0x0012, /**< rfc5766 - XOR-PEER-ADDRESS */
+ tnet_stun_attr_type_data = 0x0013, /**< rfc5766 - DATA */
+ tnet_stun_attr_type_xor_relayed_address = 0x0016, /**< rfc5766 - XOR-RELAYED-ADDRESS */
+ tnet_stun_attr_type_even_port = 0x0018, /**< rfc5766 - EVEN-PORT */
+ tnet_stun_attr_type_requested_transport = 0x0019, /**< rfc5766 - REQUESTED-TRANSPORT */
+ tnet_stun_attr_type_dont_fragment = 0x001A, /**< rfc5766 - DONT-FRAGMENT */
+ tnet_stun_attr_type_reserved3 = 0x0021, /**< rfc5766 - Reserved (was TIMER-VAL) */
+ tnet_stun_attr_type_reservation_token = 0x0022, /**< rfc5766 - RESERVATION-TOKEN */
+
+ /* RFC 5245 */
+ tnet_stun_attr_type_ice_priority = 0x0024, /**< 21.2. STUN Attributes */
+ tnet_stun_attr_type_ice_use_candidate = 0x0025, /**< 21.2. STUN Attributes */
+ tnet_stun_attr_type_ice_controlled = 0x8029, /**< 21.2. STUN Attributes */
+ tnet_stun_attr_type_ice_controlling = 0x802A, /**< 21.2. STUN Attributes */
+
+ /* rfc6062 */
+ tnet_stun_attr_type_connection_id = 0x002a, /**< 6.2. New STUN Attributes */
+} tnet_stun_attr_type_t;
+
+
+/**@ingroup tnet_stun_group
+* List of all supported STUN message types.
+*/
+typedef enum tnet_stun_pkt_type_e {
+ /* RFC 5389 - 6. STUN Message Structure
+
+ The message type defines the message class (request, success
+ response, failure response, or indication) and the message method
+ (the primary function) of the STUN message. Although there are four
+ message classes, there are only two types of transactions in STUN:
+ request/response transactions (which consist of a request message and
+ a response message) and indication transactions (which consist of a
+ single indication message). Response classes are split into error
+ and success responses to aid in quickly processing the STUN message.
+
+ The message type field is decomposed further into the following
+ structure:
+
+ 0 1
+ 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
+ |M |M |M|M|M|C|M|M|M|C|M|M|M|M|
+ |11|10|9|8|7|1|6|5|4|0|3|2|1|0|
+ +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ tnet_stun_pkt_type_binding_request = (tnet_stun_method_binding | tnet_stun_mask_request),
+ tnet_stun_pkt_type_binding_indication = (tnet_stun_method_binding | tnet_stun_mask_indication),
+ tnet_stun_pkt_type_binding_success_response = (tnet_stun_method_binding | tnet_stun_mask_success),
+ tnet_stun_pkt_type_binding_error_response = (tnet_stun_method_binding | tnet_stun_mask_error),
+
+ tnet_stun_pkt_type_allocate_request = (tnet_stun_method_allocate | tnet_stun_mask_request),
+ tnet_stun_pkt_type_allocate_indication = (tnet_stun_method_allocate | tnet_stun_mask_indication),
+ tnet_stun_pkt_type_allocate_success_response = (tnet_stun_method_allocate | tnet_stun_mask_success),
+ tnet_stun_pkt_type_allocate_error_response = (tnet_stun_method_allocate | tnet_stun_mask_error),
+
+ tnet_stun_pkt_type_refresh_request = (tnet_stun_method_refresh | tnet_stun_mask_request),
+ tnet_stun_pkt_type_refresh_indication = (tnet_stun_method_refresh | tnet_stun_mask_indication),
+ tnet_stun_pkt_type_refresh_success_response = (tnet_stun_method_refresh | tnet_stun_mask_success),
+ tnet_stun_pkt_type_refresh_error_response = (tnet_stun_method_refresh | tnet_stun_mask_error),
+
+ tnet_stun_pkt_type_send_indication = (tnet_stun_method_send | tnet_stun_mask_indication),
+
+ tnet_stun_pkt_type_data_indication = (tnet_stun_method_data | tnet_stun_mask_indication),
+
+ tnet_stun_pkt_type_createpermission_request = (tnet_stun_method_createpermission | tnet_stun_mask_request),
+ tnet_stun_pkt_type_createpermission_indication = (tnet_stun_method_createpermission | tnet_stun_mask_indication),
+ tnet_stun_pkt_type_createpermission_success_response = (tnet_stun_method_createpermission | tnet_stun_mask_success),
+ tnet_stun_pkt_type_createpermission_error_response = (tnet_stun_method_createpermission | tnet_stun_mask_error),
+
+ tnet_stun_pkt_type_channelbind_request = (tnet_stun_method_channelbind | tnet_stun_mask_request),
+ tnet_stun_pkt_type_channelbind_indication = (tnet_stun_method_channelbind | tnet_stun_mask_indication),
+ tnet_stun_pkt_type_channelbind_success_response = (tnet_stun_method_channelbind | tnet_stun_mask_success),
+ tnet_stun_pkt_type_channelbind_error_response = (tnet_stun_method_channelbind | tnet_stun_mask_error),
+
+ tnet_stun_pkt_type_connect_request = (tnet_stun_method_connect | tnet_stun_mask_request),
+ tnet_stun_pkt_type_connect_indication = (tnet_stun_method_connect | tnet_stun_mask_indication),
+ tnet_stun_pkt_type_connect_success_response = (tnet_stun_method_connect | tnet_stun_mask_success),
+ tnet_stun_pkt_type_connect_error_response = (tnet_stun_method_connect | tnet_stun_mask_error),
+
+ tnet_stun_pkt_type_connectionbind_request = (tnet_stun_method_connectionbind | tnet_stun_mask_request),
+ tnet_stun_pkt_type_connectionbind_indication = (tnet_stun_method_connectionbind | tnet_stun_mask_indication),
+ tnet_stun_pkt_type_connectionbind_success_response = (tnet_stun_method_connectionbind | tnet_stun_mask_success),
+ tnet_stun_pkt_type_connectionbind_error_response = (tnet_stun_method_connectionbind | tnet_stun_mask_error),
+
+ tnet_stun_pkt_type_connectionattempt_indication = (tnet_stun_method_connectionattempt | tnet_stun_mask_indication),
+}
+tnet_stun_pkt_type_t;
+
+/* RFC 5389 - 7.2.1. Sending over UDP
+ A client SHOULD retransmit a STUN request message starting with an
+ interval of RTO ("Retransmission TimeOut"), doubling after each
+ retransmission.
+
+ e.g. 0 ms, 500 ms, 1500 ms, 3500 ms, 7500ms, 15500 ms, and 31500 ms
+ */
+#define kStunUdpRetransmitTimoutMinInMs 500
+#define kStunUdpRetransmitTimoutMaxInMs 31500
+
+// rfc5766 - 2.2. Allocations
+#if !defined(kTurnAllocationTimeOutInSec)
+# define kTurnAllocationTimeOutInSec 600 /* 10min */ // FIXME
+#endif /* kTurnAllocationTimeOutInSec */
+
+// rfc5766 - 2.3. Permissions
+#if !defined(kTurnPermissionTimeOutInSec)
+# define kTurnPermissionTimeOutInSec 300 /* 5min */
+#endif /* kTurnPermissionTimeOutInSec */
+
+// rfc5766 - 2.5. Channels
+#if !defined(kTurnChannelBindingTimeOutInSec)
+# define kTurnChannelBindingTimeOutInSec 600 /* 10min */
+#endif /* kTurnChannelBindingTimeOutInSec */
+
+// rfc5766 - 11.4. The ChannelData Message
+#if !defined(kStunChannelDataHdrSizeInOctets)
+# define kStunChannelDataHdrSizeInOctets 4
+#endif /* kStunChannelDataHdrSizeInOctets */
+
+// Not part of the standard
+typedef enum tnet_stun_state_e {
+ tnet_stun_state_none,
+ tnet_stun_state_trying,
+ tnet_stun_state_ok,
+ tnet_stun_state_nok
+} tnet_stun_state_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_STUN_TYPES_H */
diff --git a/tinyNET/src/stun/tnet_stun_utils.c b/tinyNET/src/stun/tnet_stun_utils.c
new file mode 100644
index 0000000..8e35075
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_utils.c
@@ -0,0 +1,201 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#include "stun/tnet_stun_utils.h"
+#include "stun/tnet_stun_pkt.h"
+#include "stun/tnet_stun_attr.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+int tnet_stun_utils_inet_pton(tsk_bool_t b_v6, const char* p_src, tnet_stun_addr_t* p_dst)
+{
+ int ret;
+ if (!p_src || !p_dst) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = tnet_inet_pton(b_v6 ? AF_INET6 : AF_INET, p_src, *p_dst) != 1)) { // success == 1
+ TSK_DEBUG_ERROR("tnet_inet_pton() with error code = %d", ret);
+ return -3;
+ }
+ return 0;
+}
+
+int tnet_stun_utils_inet_ntop(tsk_bool_t b_v6, const tnet_stun_addr_t* pc_src, tnet_ip_t* p_dst)
+{
+ if (!pc_src || !p_dst) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (tnet_inet_ntop(b_v6 ? AF_INET6 : AF_INET, *pc_src, *p_dst, sizeof(*p_dst)) == tsk_null) {
+ TSK_DEBUG_ERROR("tnet_inet_ntop() failed");
+ return -2;
+ }
+ return 0;
+}
+
+int tnet_stun_utils_transac_id_rand(tnet_stun_transac_id_t* p_transac_id)
+{
+ tsk_size_t u;
+ static tsk_size_t __u_size = sizeof(tnet_stun_transac_id_t);
+ static long __l_chan_num = 0;
+
+ tsk_atomic_inc(&__l_chan_num);
+
+ if (!p_transac_id) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ for (u = 0; (u < __u_size) && (u < sizeof(long)); ++u) {
+ *(((uint8_t*)p_transac_id) + u) = (__l_chan_num >> (u << 3)) & 0xFF;
+ }
+ for (u = sizeof(long); u < __u_size; ++u) {
+ *(((uint8_t*)p_transac_id) + u) = rand() % 0xFF;
+ }
+ return 0;
+}
+
+int tnet_stun_utils_buff_cmp(const uint8_t* pc_buf1_ptr, tsk_size_t n_buff1_size, const uint8_t* pc_buf2_ptr, tsk_size_t n_buff2_size)
+{
+ int ret;
+ tsk_size_t u;
+ if (!pc_buf1_ptr || !pc_buf2_ptr || (n_buff1_size != n_buff2_size)) {
+ return -1;
+ }
+ for (u = 0; u < n_buff1_size; ++u) {
+ if ((ret = (pc_buf1_ptr[u] - pc_buf2_ptr[u]))) {
+ return ret;
+ }
+ }
+ return 0;
+}
+
+int tnet_stun_utils_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const struct tnet_stun_pkt_s* pc_stun_req, struct sockaddr* p_addr_server, struct tnet_stun_pkt_s** pp_stun_resp)
+{
+ int ret = -1;
+ uint16_t i, rto = RTO;
+ struct timeval tv;
+ fd_set set;
+ void* p_buff_ptr = tsk_null;
+ tsk_size_t u_buff_size;
+
+ if (!pc_stun_req || !p_addr_server || !pp_stun_resp) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ /* RFC 5389 - 7.2.1. Sending over UDP
+ STUN indications are not retransmitted; thus, indication transactions over UDP
+ are not reliable.
+ */
+ *pp_stun_resp = tsk_null;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ if ((ret = tnet_stun_pkt_get_size_in_octetunits_with_padding(pc_stun_req, &u_buff_size))) {
+ goto bail;
+ }
+ u_buff_size += kStunBuffMinPad;
+ if (!(p_buff_ptr = tsk_malloc(u_buff_size))) {
+ goto bail;
+ }
+ if ((ret = tnet_stun_pkt_write_with_padding(pc_stun_req, p_buff_ptr, u_buff_size, &u_buff_size))) {
+ goto bail;
+ }
+
+ /* RFC 5389 - 7.2.1. Sending over UDP
+ A client SHOULD retransmit a STUN request message starting with an
+ interval of RTO ("Retransmission TimeOut"), doubling after each
+ retransmission.
+
+ e.g. 0 ms, 500 ms, 1500 ms, 3500 ms, 7500ms, 15500 ms, and 31500 ms
+ */
+ for (i = 0; i < Rc; i++) {
+ tv.tv_sec += rto/1000;
+ tv.tv_usec += (rto% 1000) * 1000;
+ if (tv.tv_usec >= 1000000) {
+ tv.tv_usec -= 1000000;
+ tv.tv_sec++;
+ }
+
+ FD_ZERO(&set);
+ FD_SET(localFD, &set);
+
+ if ((ret = tnet_sockfd_sendto(localFD, p_addr_server, p_buff_ptr, u_buff_size))) {
+ // do nothing... not an error
+ }
+
+ if ((ret = select(localFD+1, &set, NULL, NULL, &tv)) < 0) {
+ goto bail;
+ }
+ else if (ret == 0) {
+ /* timeout */
+ TSK_DEBUG_INFO("STUN request timedout at %d", i);
+ rto *= 2;
+ continue;
+ }
+ else if (FD_ISSET(localFD, &set)) {
+ /* there is data to read */
+
+ unsigned int len = 0;
+ void* data = 0;
+
+ TSK_DEBUG_INFO("STUN request got response");
+
+ /* Check how how many bytes are pending */
+ if ((ret = tnet_ioctlt(localFD, FIONREAD, &len)) < 0) {
+ goto bail;
+ }
+
+ if(len == 0) {
+ TSK_DEBUG_INFO("tnet_ioctlt() returent zero bytes");
+ continue;
+ }
+
+ /* Receive pending data */
+ data = tsk_malloc(len);
+ if ((ret = tnet_sockfd_recvfrom(localFD, data, len, 0, p_addr_server)) < 0) {
+ TSK_FREE(data);
+
+ TSK_DEBUG_ERROR("Recv STUN dgrams failed with error code:%d", tnet_geterrno());
+ goto bail;
+ }
+
+ /* Parse the incoming response. */
+ ret = tnet_stun_pkt_read(data, (tsk_size_t)ret, pp_stun_resp);
+ TSK_FREE(data);
+ if (*pp_stun_resp) {
+ if (tnet_stun_utils_transac_id_cmp((*pp_stun_resp)->transac_id, pc_stun_req->transac_id) != 0) {
+ /* Not same transaction id */
+ TSK_OBJECT_SAFE_FREE(*pp_stun_resp);
+ continue;
+ }
+ }
+ goto bail;
+ }
+ else {
+ continue;
+ }
+ }
+
+bail:
+ TSK_FREE(p_buff_ptr);
+ return (*pp_stun_resp) ? 0 : -4;
+}
diff --git a/tinyNET/src/stun/tnet_stun_utils.h b/tinyNET/src/stun/tnet_stun_utils.h
new file mode 100644
index 0000000..c2999c7
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_utils.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_STUN_UTILS_H
+#define TNET_STUN_UTILS_H
+
+#include "tinynet_config.h"
+#include "stun/tnet_stun_types.h"
+
+#include "tnet_types.h"
+
+struct tnet_stun_pkt_s;
+
+TNET_BEGIN_DECLS
+
+TINYNET_API int tnet_stun_utils_inet_pton(tsk_bool_t b_v6, const char* p_src, tnet_stun_addr_t* p_dst);
+#define tnet_stun_utils_inet_pton_v4(p_src, p_dst) tnet_stun_utils_inet_pton(tsk_false, (p_src), (p_dst))
+#define tnet_stun_utils_inet_pton_v6(p_src, p_dst) tnet_stun_utils_inet_pton(tsk_true, (p_src), (p_dst))
+TINYNET_API int tnet_stun_utils_inet_ntop(tsk_bool_t b_v6, const tnet_stun_addr_t* pc_src, tnet_ip_t* p_dst);
+#define tnet_stun_utils_inet_ntop_v4(pc_src, p_dst) tnet_stun_utils_inet_ntop(tsk_false, (pc_src), (p_dst))
+#define tnet_stun_utils_inet_ntop_v6(pc_src, p_dst) tnet_stun_utils_inet_ntop(tsk_true, (pc_src), (p_dst))
+TINYNET_API int tnet_stun_utils_transac_id_rand(tnet_stun_transac_id_t* p_transac_id);
+TINYNET_API int tnet_stun_utils_buff_cmp(const uint8_t* pc_buf1_ptr, tsk_size_t n_buff1_size, const uint8_t* pc_buf2_ptr, tsk_size_t n_buff2_size);
+#define tnet_stun_utils_transac_id_cmp(pc_tid1, pc_tid2) tnet_stun_utils_buff_cmp((pc_tid1), sizeof(tnet_stun_transac_id_t), (pc_tid2), sizeof(tnet_stun_transac_id_t))
+#define tnet_stun_utils_transac_id_equals(pc_tid1, pc_tid2) (tnet_stun_utils_transac_id_cmp((pc_tid1), (pc_tid2)) == 0)
+int tnet_stun_utils_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const struct tnet_stun_pkt_s* pc_stun_req, struct sockaddr* p_addr_server, struct tnet_stun_pkt_s** pp_stun_resp);
+
+TNET_END_DECLS
+
+#endif /* TNET_STUN_UTILS_H */
diff --git a/tinyNET/src/tinynet.h b/tinyNET/src/tinynet.h
new file mode 100644
index 0000000..63df285
--- /dev/null
+++ b/tinyNET/src/tinynet.h
@@ -0,0 +1,59 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tinynet.h
+ * @brief API functions.
+ *
+ */
+#ifndef TNET_TINYNET_H
+#define TNET_TINYNET_H
+
+/* === tinySAK === */
+#include "tsk.h"
+
+/* === tinyNET === */
+
+#include "tnet.h"
+#include "tnet_endianness.h"
+#include "tnet_nat.h"
+#include "tnet_socket.h"
+#include "tnet_transport.h"
+#include "tnet_proxy_plugin.h"
+
+#include "stun/tnet_stun.h"
+
+#include "ice/tnet_ice_event.h"
+#include "ice/tnet_ice_candidate.h"
+#include "ice/tnet_ice_ctx.h"
+
+#include "dns/tnet_dns.h"
+#include "dns/tnet_dns_naptr.h"
+#include "dns/tnet_dns_regexp.h"
+#include "dns/tnet_dns_resolvconf.h"
+
+#include "dhcp/tnet_dhcp.h"
+#include "dhcp/tnet_dhcp_option_sip.h"
+
+#include "dhcp6/tnet_dhcp6.h"
+#include "dhcp6/tnet_dhcp6_option.h"
+
+
+#endif /* TNET_TINYNET_H */
+
diff --git a/tinyNET/src/tinynet_config.h b/tinyNET/src/tinynet_config.h
new file mode 100644
index 0000000..813c2c0
--- /dev/null
+++ b/tinyNET/src/tinynet_config.h
@@ -0,0 +1,151 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tinynet_config.h
+ * @brief Global configuration file.
+ *
+ * This file incude all your preferences or configuration. All specific configuration
+ * must be defined in this file. You must include this file in all your header files.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef _TINYNET_H_
+#define _TINYNET_H_
+
+#ifdef __SYMBIAN32__
+#undef _WIN32 /* Because of WINSCW */
+#endif
+
+// Windows (XP/Vista/7/CE and Windows Mobile) macro definition.
+#if defined(WIN32)|| defined(_WIN32) || defined(_WIN32_WCE)
+# define TNET_UNDER_WINDOWS 1
+# if defined(_WIN32_WCE) || defined(UNDER_CE)
+# define TNET_UNDER_WINDOWS_CE 1
+# endif
+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP)
+# define TNET_UNDER_WINDOWS_RT 1
+# if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+# define TNET_UNDER_WINDOWS_PHONE 1
+# endif
+# endif
+# define TNET_UNDER_WINDOWS_DESKTOP (TNET_UNDER_WINDOWS && !TNET_UNDER_WINDOWS_CE && !TNET_UNDER_WINDOWS_RT && !TNET_UNDER_WINDOWS_PHONE)
+#endif
+
+// OS X or iOS
+#if defined(__APPLE__)
+# define TNET_UNDER_APPLE 1
+# include <TargetConditionals.h>
+# include <Availability.h>
+#endif
+#if TARGET_OS_MAC
+# define TNET_UNDER_MAC 1
+#endif
+#if TARGET_OS_IPHONE
+# define TNET_UNDER_IPHONE 1
+#endif
+#if TARGET_IPHONE_SIMULATOR
+# define TNET_UNDER_IPHONE_SIMULATOR 1
+#endif
+
+/**@def TINYNET_API
+* Used on Windows and Sysbian systems to export public functions.
+*/
+#if !defined(__GNUC__) && defined(TINYNET_EXPORTS)
+# define TINYNET_API __declspec(dllexport)
+# define TINYNET_GEXTERN extern __declspec(dllexport)
+#elif !defined(__GNUC__) && !defined(TINYNET_IMPORTS_IGNORE)
+# define TINYNET_API __declspec(dllimport)
+# define TINYNET_GEXTERN __declspec(dllimport)
+#else
+# define TINYNET_API
+# define TINYNET_GEXTERN extern
+#endif
+
+/* define "TNET_DEPRECATED(func)" macro */
+#if defined(__GNUC__)
+# define TNET_DEPRECATED(func) __attribute__ ((deprecated)) func
+#elif defined(_MSC_VER)
+# define TNET_DEPRECATED(func) __declspec(deprecated) func
+#else
+# pragma message("WARNING: Deprecated not supported for this compiler")
+# define TNET_DEPRECATED(func) func
+#endif
+
+/* Guards against C++ name mangling */
+#ifdef __cplusplus
+# define TNET_BEGIN_DECLS extern "C" {
+# define TNET_END_DECLS }
+#else
+# define TNET_BEGIN_DECLS
+# define TNET_END_DECLS
+#endif
+
+#if defined(_MSC_VER)
+# define TNET_INLINE __forceinline
+#elif defined(__GNUC__) && !defined(__APPLE__)
+# define TNET_INLINE __inline
+#else
+# define TNET_INLINE
+#endif
+
+/* have poll()? */
+/* Do not use WSAPoll event if it's supported under Vista */
+#if !HAVE_CONFIG_H
+# if ANDROID || defined(__APPLE__)
+# define USE_POLL 1
+# define HAVE_POLL 1
+# define HAVE_POLL_H 1
+# endif
+#endif
+
+/* Used in TURN/STUN2 attributes. */
+#define TNET_SOFTWARE "IM-client/OMA1.0 doubango/v2.0.0"
+#define TNET_IANA_PEN 35368 /**< PEN number assigned by the IANA.
+ The list of assigned numbers could be found here http://www.iana.org/assignments/enterprise-numbers. */
+#define TNET_RESOLV_CONF_PATH "/etc/resolv.conf" /**< Path to "/resolv.conf". */
+
+#include <stdint.h>
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#elif defined(__APPLE__)
+# define HAVE_GETIFADDRS 1
+# define HAVE_IFADDRS_H 1
+# define HAVE_DNS_H 1
+# define HAVE_NET_ROUTE_H 1
+# define HAVE_NET_IF_DL_H 1
+# define HAVE_STRUCT_RT_METRICS 1
+# define HAVE_STRUCT_SOCKADDR_DL 1
+# define HAVE_SYS_PARAM_H 1
+# define TNET_HAVE_SS_LEN 1
+# define TNET_HAVE_SA_LEN 0
+# if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)
+# define HAVE_GSSAPI_H 1
+# endif
+#endif
+
+#endif /* _TINYNET_H_ */
+
+
diff --git a/tinyNET/src/tls/tnet_dtls.c b/tinyNET/src/tls/tnet_dtls.c
new file mode 100644
index 0000000..78d4190
--- /dev/null
+++ b/tinyNET/src/tls/tnet_dtls.c
@@ -0,0 +1,798 @@
+/*
+* Copyright (C) 2013-2015 Mamadou DIOP
+* Copyright (C) 2013-2015 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_dtls.c
+ * @brief DTLS utilitity functions, based on openssl.
+ */
+#include "tnet_dtls.h"
+#include "tnet_tls.h"
+#include "tnet_utils.h"
+
+#include "tsk_object.h"
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_time.h"
+#include "tsk_safeobj.h"
+#include "tsk_debug.h"
+
+typedef struct tnet_dtls_socket_s
+{
+ TSK_DECLARE_OBJECT;
+
+ struct tnet_socket_s* wrapped_sock; /* not owner: do not try to close */
+ tsk_bool_t verify_peer;
+ tsk_bool_t use_srtp;
+ tsk_bool_t handshake_completed;
+ tsk_bool_t handshake_started;
+ tsk_bool_t handshake_storedata; // whether to store handshaking data or to send it to the remote party
+ tnet_dtls_setup_t setup;
+
+ struct {
+ void* ptr;
+ tsk_size_t size;
+ tsk_size_t count;
+ } handshake_data;
+
+ struct{
+ const void* usrdata;
+ tnet_dtls_socket_cb_f func;
+ } cb;
+
+ struct{
+ tnet_fingerprint_t fp;
+ tnet_dtls_hash_type_t hash;
+ struct sockaddr_storage addr;
+ } remote;
+ struct{
+ tnet_fingerprint_t fp;
+ tnet_dtls_hash_type_t hash;
+ } local;
+
+#if HAVE_OPENSSL
+ SSL *ssl;
+ BIO* rbio;
+ BIO* wbio;
+#endif
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_dtls_socket_t;
+
+#define _tnet_dtls_socket_do_handshake(self) tnet_dtls_socket_do_handshake(self, tsk_null)
+#define _tnet_dtls_socket_raise_event(self, type, data, size) ((self) && (self)->cb.func ? (self)->cb.func((self)->cb.usrdata, (type), (self), (data), (size)) : 0)
+#define _tnet_dtls_socket_raise_event_dataless(self, type) _tnet_dtls_socket_raise_event((self), (type), tsk_null, 0)
+
+tsk_bool_t tnet_dtls_is_srtp_supported()
+{
+#if HAVE_OPENSSL_DTLS_SRTP
+ return tsk_true;
+#else
+ return tsk_false;
+#endif
+}
+
+tsk_bool_t tnet_dtls_is_supported()
+{
+#if HAVE_OPENSSL_DTLS
+ return tsk_true;
+#else
+ return tsk_false;
+#endif
+}
+
+
+#if HAVE_OPENSSL
+
+static tsk_bool_t _tnet_dtls_is_fingerprint_matching(X509* cert, tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash);
+
+static int _tnet_dtls_verify_cert(int preverify_ok, X509_STORE_CTX *ctx)
+{
+ SSL *ssl;
+ tnet_dtls_socket_t* socket;
+
+ TSK_DEBUG_INFO("_tnet_dtls_verify_cert");
+
+ ssl = X509_STORE_CTX_get_app_data(ctx);
+ socket = (tnet_dtls_socket_t*)SSL_get_app_data(ssl);
+ if (!ssl || !socket){
+ TSK_DEBUG_ERROR("Not expected");
+ return 0;
+ }
+ tsk_safeobj_lock(socket);
+ if (_tnet_dtls_is_fingerprint_matching(ctx->cert, &socket->remote.fp, socket->remote.hash) == tsk_false) {
+ TSK_DEBUG_ERROR("Failed to match fingerprint");
+ tsk_safeobj_unlock(socket);
+ return 0;
+ }
+ tsk_safeobj_unlock(socket);
+ return 1;
+}
+
+static const EVP_MD *_tnet_dtls_get_hash_evp(tnet_dtls_hash_type_t hash)
+{
+ switch (hash){
+ case tnet_dtls_hash_type_md5: return EVP_md5();
+ case tnet_dtls_hash_type_sha1: return EVP_sha1();
+ case tnet_dtls_hash_type_sha256: return EVP_sha256();
+ case tnet_dtls_hash_type_sha512: return EVP_sha512();
+ default: TSK_DEBUG_ERROR("Invalid parameter: %d not valid as hash type", hash); return tsk_null;
+ }
+}
+
+static int _tnet_dtls_get_fingerprint(X509* cert, const EVP_MD *evp, tnet_fingerprint_t* fingerprint)
+{
+ if (!cert || !evp || !fingerprint){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ else{
+ unsigned len = 0, i, j;
+ tnet_fingerprint_t fp;
+
+ if (X509_digest(cert, evp, fp, &len) != 1 || len <= 0){
+ TSK_DEBUG_ERROR("X509_digest() failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ return -2;
+ }
+ for (i = 0, j = 0; i < len; ++i, j += 3){
+ sprintf((char*)&(*fingerprint)[j], (i == (len - 1)) ? "%.2X" : "%.2X:", fp[i]);
+ }
+ (*fingerprint)[len * 3] = '\0';
+ return 0;
+ }
+}
+
+static tsk_bool_t _tnet_dtls_is_fingerprint_matching(X509* cert, tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash)
+{
+ const EVP_MD* evp;
+ tnet_fingerprint_t fp;
+ int ret;
+
+ if (!cert || !fingerprint){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_false;
+ }
+
+ if (!(evp = _tnet_dtls_get_hash_evp(hash))){
+ return tsk_false;
+ }
+ if ((ret = _tnet_dtls_get_fingerprint(cert, evp, &fp))){
+ return tsk_false;
+ }
+ if (!tsk_striequals(fp, fingerprint)){
+ TSK_DEBUG_ERROR("DTLS certificate fingerprints mismatch: [%s]#[%s]", fp, *fingerprint);
+ return tsk_false;
+ }
+ return tsk_true;
+}
+
+static tsk_bool_t _tnet_dtls_socket_is_remote_cert_fp_match(tnet_dtls_socket_t* socket)
+{
+ if (!socket){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_false;
+ }
+ else if (socket->verify_peer){
+ X509* cert;
+
+ if (!(cert = SSL_get_peer_certificate(socket->ssl))){
+ if (socket->verify_peer){ // print error only if verify certs is enabled
+ TSK_DEBUG_ERROR("Failed to get peer certificate [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ }
+ return tsk_false;
+ }
+ if (!_tnet_dtls_is_fingerprint_matching(cert, &socket->remote.fp, socket->remote.hash)){
+ X509_free(cert);
+ return tsk_false;
+ }
+ X509_free(cert);
+
+ if (SSL_get_verify_result(socket->ssl) != X509_V_OK){
+ TSK_DEBUG_ERROR("SSL_get_verify_result()#X509_V_OK [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ return tsk_false;
+ }
+ }
+
+ return tsk_true;
+}
+
+#endif /* HAVE_OPENSSL */
+
+tnet_dtls_hash_type_t tnet_dtls_get_hash_from_string(const char* hash)
+{
+ if (hash){
+ int32_t i;
+ for (i = 0; i < TNET_DTLS_HASH_TYPE_MAX; ++i){
+ if (tsk_striequals(TNET_DTLS_HASH_NAMES[i], hash)){
+ return (tnet_dtls_hash_type_t)i;
+ }
+ }
+ }
+ return tnet_dtls_hash_type_none;
+}
+
+tnet_dtls_setup_t tnet_dtls_get_setup_from_string(const char* setup)
+{
+ if (setup){
+ int32_t i;
+ for (i = 0; i < TNET_DTLS_SETUP_MAX; ++i){
+ if (tsk_striequals(TNET_DTLS_SETUP_NAMES[i], setup)){
+ return (tnet_dtls_setup_t)i;
+ }
+ }
+ }
+ return tnet_dtls_setup_none;
+}
+
+int tnet_dtls_get_fingerprint(const char* certfile, tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash)
+{
+#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
+ TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
+ return -200;
+#else
+ {
+ X509* x509;
+ BIO* bio;
+ int ret = 0;
+ const EVP_MD *evp;
+
+ if (tsk_strnullORempty(certfile) || !fingerprint){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!(evp = _tnet_dtls_get_hash_evp(hash))){
+ return -1;
+ }
+
+ x509 = tsk_null;
+ bio = tsk_null;
+
+ if (!(bio = BIO_new(BIO_s_file()))){
+ TSK_DEBUG_ERROR("BIO_new(BIO_s_file()) failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ ret = -3;
+ goto bail;
+ }
+ if (BIO_read_filename(bio, certfile) != 1){
+ TSK_DEBUG_ERROR("BIO_read_filename(%s) failed [%s]", certfile, ERR_error_string(ERR_get_error(), tsk_null));
+ ret = -4;
+ goto bail;
+ }
+ if (!(x509 = PEM_read_bio_X509(bio, tsk_null, 0, tsk_null))){
+ TSK_DEBUG_ERROR("PEM_read_bio() failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ ret = -5;
+ goto bail;
+ }
+ if ((ret = _tnet_dtls_get_fingerprint(x509, evp, fingerprint))){
+ goto bail;
+ }
+
+ bail:
+ if (bio){
+ BIO_free_all(bio);
+ }
+ return ret;
+ }
+#endif
+}
+
+tnet_dtls_socket_handle_t* tnet_dtls_socket_create(struct tnet_socket_s* wrapped_sock, struct ssl_ctx_st* ssl_ctx)
+{
+#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
+ TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
+ return tsk_null;
+#else
+ tnet_dtls_socket_t* socket;
+
+ if (!wrapped_sock || !ssl_ctx){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+ if ((socket = tsk_object_new(tnet_dtls_socket_def_t))) {
+ const tsk_bool_t set_mtu = TNET_SOCKET_TYPE_IS_DGRAM(wrapped_sock->type) || 1; //!\ This is required even if the local transport is TCP/TLS because the relayed (TURN) transport could be UDP
+ socket->wrapped_sock = tsk_object_ref(wrapped_sock);
+ if (!(socket->ssl = SSL_new(ssl_ctx))) {
+ TSK_DEBUG_ERROR("SSL_new(CTX) failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ TSK_OBJECT_SAFE_FREE(socket);
+ return tsk_null;
+ }
+ if (set_mtu) {
+ SSL_set_options(socket->ssl, SSL_OP_NO_QUERY_MTU);
+ SSL_set_mtu(socket->ssl, TNET_DTLS_MTU - 28);
+ socket->ssl->d1->mtu = TNET_DTLS_MTU - 28;
+ }
+ if (!(socket->rbio = BIO_new(BIO_s_mem())) || !(socket->wbio = BIO_new(BIO_s_mem()))){
+ TSK_DEBUG_ERROR("BIO_new_socket(%d) failed [%s]", socket->wrapped_sock->fd, ERR_error_string(ERR_get_error(), tsk_null));
+ if (socket->rbio){
+ BIO_free(socket->rbio);
+ }
+ if (socket->wbio){
+ BIO_free(socket->wbio);
+ }
+ TSK_OBJECT_SAFE_FREE(socket);
+ return tsk_null;
+ }
+ BIO_set_mem_eof_return(socket->rbio, -1);
+ BIO_set_mem_eof_return(socket->wbio, -1);
+ SSL_set_bio(socket->ssl, socket->rbio, socket->wbio);
+ SSL_set_mode(socket->ssl, SSL_MODE_AUTO_RETRY);
+ SSL_set_read_ahead(socket->ssl, 1);
+ if (set_mtu) {
+ BIO_ctrl(SSL_get_wbio(socket->ssl), BIO_CTRL_DGRAM_SET_MTU, TNET_DTLS_MTU - 28, NULL);
+ }
+
+ if ((socket->verify_peer = (SSL_CTX_get_verify_mode(ssl_ctx) != SSL_VERIFY_NONE))){
+ TSK_DEBUG_INFO("SSL cert verify: ON");
+ socket->verify_peer = tsk_true;
+ SSL_set_verify(socket->ssl, (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), _tnet_dtls_verify_cert);
+ }
+ else {
+ TSK_DEBUG_ERROR("Verity not enabled");
+ }
+
+ SSL_set_app_data(socket->ssl, socket);
+ }
+ return socket;
+#endif
+}
+
+tnet_fd_t tnet_dtls_socket_get_fd(const tnet_dtls_socket_handle_t* handle)
+{
+ return handle ? ((const tnet_dtls_socket_t*)handle)->wrapped_sock->fd : TNET_INVALID_FD;
+}
+
+const struct sockaddr_storage* tnet_dtls_socket_get_remote_addr(const tnet_dtls_socket_handle_t* handle)
+{
+ return handle ? &((const tnet_dtls_socket_t*)handle)->remote.addr : tsk_null;
+}
+
+int tnet_dtls_socket_set_callback(tnet_dtls_socket_handle_t* handle, const void* usrdata, tnet_dtls_socket_cb_f func)
+{
+ tnet_dtls_socket_t* socket = handle;
+
+ if (!socket){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ socket->cb.usrdata = usrdata;
+ socket->cb.func = func;
+ return 0;
+}
+
+int tnet_dtls_socket_set_remote_fingerprint(tnet_dtls_socket_handle_t* handle, const tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash)
+{
+ tnet_dtls_socket_t* socket = handle;
+
+ if (!socket || !fingerprint){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ memcpy(socket->remote.fp, &(*fingerprint)[0], sizeof(tnet_fingerprint_t));
+ socket->remote.hash = hash;
+ return 0;
+}
+
+/*
+rfc5764: 4.1. The use_srtp Extension
+*/
+int tnet_dtls_socket_use_srtp(tnet_dtls_socket_handle_t*handle)
+{
+#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS || !HAVE_OPENSSL_DTLS_SRTP
+ TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
+ return -200;
+#else
+ tnet_dtls_socket_t* socket = handle;
+ if (!socket){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if ((socket->use_srtp = tsk_true)){
+ if (!socket->verify_peer){
+ socket->verify_peer = tsk_true; // DTLS-SRTP requires certtificates
+ SSL_set_verify(socket->ssl, (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), _tnet_dtls_verify_cert);
+ }
+ }
+ return 0;
+#endif
+}
+
+int tnet_dtls_socket_set_setup(tnet_dtls_socket_handle_t* handle, tnet_dtls_setup_t setup)
+{
+#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
+ TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
+ return -200;
+#else
+ tnet_dtls_socket_t* socket = handle;
+ if (!socket){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ switch ((socket->setup = setup)){
+ case tnet_dtls_setup_passive:
+ SSL_set_accept_state(socket->ssl);
+ break;
+ case tnet_dtls_setup_active:
+ case tnet_dtls_setup_actpass:
+ case tnet_dtls_setup_none:
+ if (setup != tnet_dtls_setup_active){
+ TSK_DEBUG_WARN("using setup=%s is not a good idea", TNET_DTLS_SETUP_NAMES[setup]);
+ }
+ SSL_set_connect_state(socket->ssl);
+ break;
+ default:
+ TSK_DEBUG_ERROR("%d not valid value for DTLS setup", (int32_t)setup);
+ break;
+ }
+ return 0;
+#endif
+}
+
+int tnet_dtls_socket_set_store_handshakingdata(tnet_dtls_socket_handle_t* handle, tsk_bool_t handshake_storedata)
+{
+ if (!handle) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ ((tnet_dtls_socket_t*)handle)->handshake_storedata = handshake_storedata;
+ return 0;
+}
+
+int tnet_dtls_socket_get_handshakingdata(tnet_dtls_socket_handle_t* handle, const void** data, tsk_size_t *size)
+{
+ if (!handle || !data || !size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *data = ((tnet_dtls_socket_t*)handle)->handshake_data.ptr;
+ *size = ((tnet_dtls_socket_t*)handle)->handshake_data.count;
+ return 0;
+}
+
+// This function returns first DTLS record. It's useful to send handshaking data by records to avoid IP fragmentation
+int tnet_dtls_socket_get_record_first(const void* records, tsk_size_t records_size, const void** record, tsk_size_t* size)
+{
+ /* https://tools.ietf.org/html/rfc6347#section-3.2.3
+ TLS and DTLS handshake messages can be quite large(in theory up to
+ 2 ^ 24 - 1 bytes, in practice many kilobytes).By contrast, UDP
+ datagrams are often limited to <1500 bytes if IP fragmentation is not
+ desired.In order to compensate for this limitation, each DTLS
+ handshake message may be fragmented over several DTLS records, each
+ of which is intended to fit in a single IP datagram.Each DTLS
+ handshake message contains both a fragment offset and a fragment
+ length.Thus, a recipient in possession of all bytes of a handshake
+ message can reassemble the original unfragmented message. */
+ // 4.1. Record Layer - https://tools.ietf.org/html/rfc6347#section-4.1
+#define kDTLSv1RecordHdrStartIndex 11
+#define kDTLSv1RecordHdrLengthFieldLen 2 // uint16
+#define kDTLSv1RecordHdrLen (kDTLSv1RecordHdrStartIndex + kDTLSv1RecordHdrLengthFieldLen)
+
+ const uint8_t* pc_records;
+ tsk_size_t record_length;
+ if (!records || records_size < kDTLSv1RecordHdrLen || !record || !size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ pc_records = (const uint8_t*)records;
+ record_length = ((pc_records[kDTLSv1RecordHdrStartIndex] << 8) & 0xFF00) | (pc_records[kDTLSv1RecordHdrStartIndex + 1] & 0xFF);
+ *record = records;
+ *size = kDTLSv1RecordHdrLen + record_length;
+ if ((*size) > TNET_DTLS_MTU) {
+ TSK_DEBUG_WARN("DTLS record length(%u) > MTU(%u)", (unsigned)(*size), TNET_DTLS_MTU);
+ }
+
+ return 0;
+}
+
+tsk_bool_t tnet_dtls_socket_is_remote_cert_fp_match(tnet_dtls_socket_handle_t* handle)
+{
+#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
+ TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
+ return -1;
+#else
+ return _tnet_dtls_socket_is_remote_cert_fp_match((tnet_dtls_socket_t*)handle);
+#endif
+}
+
+int tnet_dtls_socket_do_handshake(tnet_dtls_socket_handle_t* handle, const struct sockaddr_storage* remote_addr)
+{
+#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
+ TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
+ return -1;
+
+#else
+ tnet_dtls_socket_t *socket = handle;
+ int ret = 0, len;
+ void* out_data;
+
+ if (!socket) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(socket);
+
+ // update remote address even if handshaking is completed
+ if (remote_addr) {
+ socket->remote.addr = *remote_addr;
+ }
+
+ if (socket->handshake_completed) {
+ TSK_DEBUG_INFO("Handshake completed");
+ ret = 0;
+ goto bail;
+ }
+
+ if (!socket->handshake_started) {
+ if ((ret = SSL_do_handshake(socket->ssl)) != 1) {
+ switch ((ret = SSL_get_error(socket->ssl, ret))) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_NONE:
+ break;
+ default:
+ TSK_DEBUG_ERROR("DTLS handshake failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_handshake_failed);
+ ret = -2;
+ goto bail;
+ }
+ }
+ socket->handshake_started = (ret == SSL_ERROR_NONE); // TODO: reset for renegotiation
+ }
+
+ if ((len = (int)BIO_get_mem_data(socket->wbio, &out_data)) > 0 && out_data) {
+ if (socket->handshake_storedata) { // e.g. when TURN is enabled we have to query handshaking data and sent it via the negotiated channel
+ if ((int)socket->handshake_data.size < len) {
+ if (!(socket->handshake_data.ptr = tsk_realloc(socket->handshake_data.ptr, len))) {
+ socket->handshake_data.size = 0;
+ socket->handshake_data.count = 0;
+ ret = -5;
+ goto bail;
+ }
+ socket->handshake_data.size = len;
+ }
+ socket->handshake_data.count = len;
+ memcpy(socket->handshake_data.ptr, out_data, len);
+ }
+ else {
+ int sentlen = 0;
+ tnet_port_t port;
+ tnet_ip_t ip;
+ tsk_bool_t is_dgram = TNET_SOCKET_TYPE_IS_DGRAM(socket->wrapped_sock->type);
+ const uint8_t *record_ptr, *records_ptr = out_data;
+ tsk_size_t record_size;
+ int records_len = len;
+
+ tnet_get_sockip_n_port((const struct sockaddr *)&socket->remote.addr, &ip, &port);
+ TSK_DEBUG_INFO("DTLS data handshake to send with len = %d, from(%.*s/%d) to(%.*s/%d)", len, (int)sizeof(socket->wrapped_sock->ip), socket->wrapped_sock->ip, socket->wrapped_sock->port, (int)sizeof(ip), ip, port);
+
+ //!\ IP fragmentation issues must be avoided even if the local transport is TCP/TLS because the relayed (TURN) transport could be UDP
+ while (records_len > 0 && (ret = tnet_dtls_socket_get_record_first(records_ptr, (tsk_size_t)records_len, (const void**)&record_ptr, &record_size)) == 0) {
+ if (is_dgram) {
+ sentlen += tnet_sockfd_sendto(socket->wrapped_sock->fd, (const struct sockaddr *)&socket->remote.addr, record_ptr, record_size);
+ }
+ else {
+ sentlen += tnet_socket_send_stream(socket->wrapped_sock, record_ptr, record_size);
+ }
+ records_len -= (int)record_size;
+ records_ptr += record_size;
+ }
+ TSK_DEBUG_INFO("DTLS data handshake sent len = %d", sentlen);
+ }
+ }
+
+ BIO_reset(socket->rbio);
+ BIO_reset(socket->wbio);
+
+ if ((socket->handshake_completed = SSL_is_init_finished(socket->ssl))) {
+ TSK_DEBUG_INFO("DTLS handshake completed");
+
+#if HAVE_OPENSSL_DTLS_SRTP
+ if (socket->use_srtp){
+#if !defined(SRTP_MAX_KEY_LEN)
+# define cipher_key_length (128 >> 3) // rfc5764 4.1.2. SRTP Protection Profiles
+# define cipher_salt_length (112 >> 3) // rfc5764 4.1.2. SRTP Protection Profiles
+ // "cipher_key_length" is also equal to srtp_profile_get_master_key_length(srtp_profile_aes128_cm_sha1_80)
+ // "cipher_salt_length" is also srtp_profile_get_master_salt_length(srtp_profile_aes128_cm_sha1_80)
+# define SRTP_MAX_KEY_LEN (cipher_key_length + cipher_salt_length)
+#endif /* SRTP_MAX_KEY_LEN */
+#define EXTRACTOR_dtls_srtp_text "EXTRACTOR-dtls_srtp"
+#define EXTRACTOR_dtls_srtp_text_len 19
+ uint8_t keying_material[SRTP_MAX_KEY_LEN << 1];
+ static const tsk_size_t keying_material_size = sizeof(keying_material);
+ /*if(socket->use_srtp)*/{
+ SRTP_PROTECTION_PROFILE *p = SSL_get_selected_srtp_profile(socket->ssl);
+ if (!p) {
+ TSK_DEBUG_ERROR("SSL_get_selected_srtp_profile() returned null [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ ret = -2;
+ goto bail;
+ }
+ // alert user
+ _tnet_dtls_socket_raise_event(socket, tnet_dtls_socket_event_type_dtls_srtp_profile_selected, p->name, tsk_strlen(p->name));
+
+ memset(keying_material, 0, sizeof(keying_material));
+
+ // rfc5764 - 4.2. Key Derivation
+ ret = SSL_export_keying_material(socket->ssl, keying_material, sizeof(keying_material), EXTRACTOR_dtls_srtp_text, EXTRACTOR_dtls_srtp_text_len, tsk_null, 0, 0);
+ if (ret != 1) {
+ // alert listener
+ _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_error);
+ TSK_DEBUG_ERROR("SSL_export_keying_material() failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ ret = -2;
+ goto bail;
+ }
+ }
+ // alert listener
+ _tnet_dtls_socket_raise_event(socket, tnet_dtls_socket_event_type_dtls_srtp_data, keying_material, keying_material_size);
+ }
+#endif /* HAVE_OPENSSL_DTLS_SRTP */
+ _tnet_dtls_socket_raise_event_dataless(socket, tnet_dtls_socket_event_type_handshake_succeed);
+ }
+ ret = 0; // clear "ret", error will directly jump to "bail:"
+bail:
+ tsk_safeobj_unlock(socket);
+ return ret;
+#endif
+}
+
+tsk_bool_t tnet_dtls_socket_is_handshake_completed(const tnet_dtls_socket_handle_t* handle)
+{
+ return (handle && ((const tnet_dtls_socket_t *)handle)->handshake_completed);
+}
+
+/*
+Handles DTLS data received over the network using standard functions (e.g. recvfrom())
+@param handle
+@param data When "use_srtp" is enabled this must point to DTLS handshake data.
+@param size DTLS data size
+@returns 0 if succeed, non-zero error code otherwise
+*/
+int tnet_dtls_socket_handle_incoming_data(tnet_dtls_socket_handle_t* handle, const void* data, tsk_size_t size)
+{
+#if !HAVE_OPENSSL || !HAVE_OPENSSL_DTLS
+ TSK_DEBUG_ERROR("OpenSSL or DTLS not enabled");
+ return -200;
+#else
+ tnet_dtls_socket_t *socket = handle;
+ int ret = 0;
+
+ if (!socket || !data || !size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(socket);
+
+ TSK_DEBUG_INFO("Receive DTLS data: %lu", (unsigned long)size);
+
+ // BIO_reset(socket->rbio);
+ // BIO_reset(socket->wbio);
+
+ if (!socket->rbio || !socket->wbio) {
+ TSK_DEBUG_ERROR("BIO not initialized yet");
+ ret = -2;
+ goto bail;
+ }
+
+ if ((ret = _tnet_dtls_socket_do_handshake(socket))) {
+ goto bail;
+ }
+
+ if ((ret = BIO_write(socket->rbio, data, (int)size)) != size) {
+ ret = SSL_get_error(socket->ssl, ret);
+ TSK_DEBUG_ERROR("BIO_write(rbio, %lu) failed [%s]", (unsigned long)size, ERR_error_string(ERR_get_error(), tsk_null));
+ ret = -1;
+ goto bail;
+ }
+
+ /*if((ret = SSL_read(socket->ssl, (void*)data, size)) <= 0){
+ switch((ret = SSL_get_error(socket->ssl, ret))){
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_NONE:
+ break;
+ default:
+ {
+ unsigned long sslErr = ERR_get_error();
+ const uint8_t* pData = (const uint8_t*)data;
+ TSK_DEBUG_ERROR("%lu = SSL_read(rbio, %u) failed [%s]", sslErr, size, ERR_error_string(ret, tsk_null));
+ // try to understand what's going on
+ // rfc6347 - 4.1. Record Layer
+ // rfc6347 - 4.2.2. Handshake Message Format
+ // rfc6347 - 4.3.2. Handshake Protocol
+ if(size > 14 && pData[0] == 0x16){ // content-type=='Handshake'
+ if(pData[13] == 0x01 && (socket->setup == tnet_dtls_setup_active || socket->setup == tnet_dtls_setup_actpass)){ // Handshake Type=='client Hello'
+ TSK_DEBUG_INFO("DTLS engine was in client mode but we are receiving 'Client Hello' messages. This is a bug in the remote peer: Re-negotiating!");
+ tnet_dtls_socket_set_setup(socket, tnet_dtls_setup_passive);
+ break;
+ }
+ else if(pData[13] == 0x02 && (socket->setup == tnet_dtls_setup_passive || socket->setup == tnet_dtls_setup_actpass)){ // Handshake Type=='server Hello'
+ TSK_DEBUG_INFO("DTLS engine was in server mode but we are receiving 'Server Hello' messages. This is a bug in the remote peer: Re-negotiating!");
+ tnet_dtls_socket_set_setup(socket, tnet_dtls_setup_active);
+ break;
+ }
+ }
+ //return -1;
+ break;
+ }
+ }
+ }*/
+
+ ret = _tnet_dtls_socket_do_handshake(socket);
+
+bail:
+ tsk_safeobj_unlock(socket);
+ return ret;
+#endif
+}
+
+
+//=================================================================================================
+// DTLS socket object definition
+//
+static tsk_object_t* tnet_dtls_socket_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dtls_socket_t *socket = self;
+ if (socket){
+ tsk_safeobj_init(socket);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dtls_socket_dtor(tsk_object_t * self)
+{
+ tnet_dtls_socket_t *socket = self;
+ if (socket){
+#if HAVE_OPENSSL
+ if (socket->rbio) {
+ //BIO_free(socket->rbio);
+ socket->rbio = tsk_null;
+ }
+ if (socket->wbio) {
+ //BIO_free(socket->wbio);
+ socket->wbio = tsk_null;
+ }
+ if (socket->ssl) {
+ SSL_shutdown(socket->ssl);
+ // https://www.openssl.org/docs/crypto/BIO_s_bio.html
+ // implicitly frees internal_bio
+ SSL_free(socket->ssl);
+ }
+#endif
+ TSK_FREE(socket->handshake_data.ptr);
+ TSK_OBJECT_SAFE_FREE(socket->wrapped_sock);
+ tsk_safeobj_deinit(socket);
+
+ TSK_DEBUG_INFO("*** tnet_dtls_socket_t destroyed ***");
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dtls_socket_def_s =
+{
+ sizeof(tnet_dtls_socket_t),
+ tnet_dtls_socket_ctor,
+ tnet_dtls_socket_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dtls_socket_def_t = &tnet_dtls_socket_def_s;
diff --git a/tinyNET/src/tls/tnet_dtls.h b/tinyNET/src/tls/tnet_dtls.h
new file mode 100644
index 0000000..e5b518c
--- /dev/null
+++ b/tinyNET/src/tls/tnet_dtls.h
@@ -0,0 +1,75 @@
+/*
+* Copyright (C) 2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_dtls.h
+ * @brief DTLS utilitity functions, based on openssl.
+ */
+#ifndef TNET_DTLS_H
+#define TNET_DTLS_H
+
+#include "tinynet_config.h"
+#include "tnet_types.h"
+
+TNET_BEGIN_DECLS
+
+struct ssl_ctx_st;
+struct tnet_socket_s;
+
+typedef void tnet_dtls_socket_handle_t;
+
+typedef enum tnet_dtls_socket_event_type_e
+{
+ tnet_dtls_socket_event_type_handshake_started,
+ tnet_dtls_socket_event_type_handshake_succeed,
+ tnet_dtls_socket_event_type_handshake_failed,
+ tnet_dtls_socket_event_type_fingerprint_mismatch,
+ tnet_dtls_socket_event_type_error,
+ tnet_dtls_socket_event_type_dtls_srtp_profile_selected, /* SRTP_AES128_CM_SHA1_80 | SRTP_AES128_CM_SHA1_32 */
+ tnet_dtls_socket_event_type_dtls_srtp_data, /* key||salt */
+}
+tnet_dtls_socket_event_type_t;
+
+typedef int (*tnet_dtls_socket_cb_f)(const void* usrdata, tnet_dtls_socket_event_type_t e, const tnet_dtls_socket_handle_t* handle, const void* data, tsk_size_t size);
+
+TINYNET_API tsk_bool_t tnet_dtls_is_srtp_supported();
+TINYNET_API tsk_bool_t tnet_dtls_is_supported();
+TINYNET_API tnet_dtls_hash_type_t tnet_dtls_get_hash_from_string(const char* hash);
+TINYNET_API tnet_dtls_setup_t tnet_dtls_get_setup_from_string(const char* setup);
+TINYNET_API int tnet_dtls_get_fingerprint(const char* certfile, tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash);
+TINYNET_API tnet_dtls_socket_handle_t* tnet_dtls_socket_create(struct tnet_socket_s* wrapped_sock, struct ssl_ctx_st* ssl_ctx);
+TINYNET_API tnet_fd_t tnet_dtls_socket_get_fd(const tnet_dtls_socket_handle_t* handle);
+TINYNET_API const struct sockaddr_storage* tnet_dtls_socket_get_remote_addr(const tnet_dtls_socket_handle_t* handle);
+TINYNET_API int tnet_dtls_socket_set_callback(tnet_dtls_socket_handle_t* handle, const void* usrdata, tnet_dtls_socket_cb_f func);
+TINYNET_API int tnet_dtls_socket_set_remote_fingerprint(tnet_dtls_socket_handle_t* handle, const tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash);
+TINYNET_API int tnet_dtls_socket_set_store_handshakingdata(tnet_dtls_socket_handle_t* handle, tsk_bool_t handshake_storedata);
+TINYNET_API int tnet_dtls_socket_get_handshakingdata(tnet_dtls_socket_handle_t* handle, const void** data, tsk_size_t *size);
+TINYNET_API int tnet_dtls_socket_get_record_first(const void* records, tsk_size_t records_size, const void** record, tsk_size_t* size);
+TINYNET_API int tnet_dtls_socket_use_srtp(tnet_dtls_socket_handle_t* handle);
+TINYNET_API int tnet_dtls_socket_set_setup(tnet_dtls_socket_handle_t* handle, tnet_dtls_setup_t setup);
+TINYNET_API tsk_bool_t tnet_dtls_socket_is_remote_cert_fp_match(tnet_dtls_socket_handle_t* handle);
+TINYNET_API int tnet_dtls_socket_do_handshake(tnet_dtls_socket_handle_t* handle, const struct sockaddr_storage* remote_addr);
+TINYNET_API tsk_bool_t tnet_dtls_socket_is_handshake_completed(const tnet_dtls_socket_handle_t* handle);
+TINYNET_API int tnet_dtls_socket_handle_incoming_data(tnet_dtls_socket_handle_t* handle, const void* data, tsk_size_t size);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dtls_socket_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DTLS_H */
diff --git a/tinyNET/src/tls/tnet_tls.c b/tinyNET/src/tls/tnet_tls.c
new file mode 100644
index 0000000..0ae520c
--- /dev/null
+++ b/tinyNET/src/tls/tnet_tls.c
@@ -0,0 +1,343 @@
+/*
+* Copyright (C) 2010-2012 Mamadou Diop.
+* Copyright (C) 2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_tls.c
+ * @brief TLS utilitity functions, based on openssl.
+ */
+#include "tnet_tls.h"
+#include "tnet_utils.h"
+
+#include "tsk_object.h"
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+#include "tsk_safeobj.h"
+
+#define TNET_TLS_TIMEOUT 2000
+#define TNET_TLS_RETRY_COUNT 10
+
+typedef struct tnet_tls_socket_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_fd_t fd; /* not owner: do not try to close */
+
+#if HAVE_OPENSSL
+ SSL *ssl;
+#endif
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_tls_socket_t;
+
+tsk_bool_t tnet_tls_is_supported()
+{
+#if HAVE_OPENSSL
+ return tsk_true;
+#else
+ return tsk_false;
+#endif
+}
+
+tnet_tls_socket_handle_t* tnet_tls_socket_create(tnet_fd_t fd, struct ssl_ctx_st* ssl_ctx)
+{
+#if !HAVE_OPENSSL
+ TSK_DEBUG_ERROR("OpenSSL not enabled");
+ return tsk_null;
+#else
+ tnet_tls_socket_t* socket;
+ if(fd <= 0 || !ssl_ctx){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+ if((socket = tsk_object_new(tnet_tls_socket_def_t))){
+ socket->fd = fd;
+ if(!(socket->ssl = SSL_new(ssl_ctx))){
+ TSK_DEBUG_ERROR("SSL_new(CTX) failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ TSK_OBJECT_SAFE_FREE(socket);
+ return tsk_null;
+ }
+ if(SSL_set_fd(socket->ssl, socket->fd) != 1){
+ TSK_DEBUG_ERROR("SSL_set_fd(%d) failed [%s]", socket->fd, ERR_error_string(ERR_get_error(), tsk_null));
+ TSK_OBJECT_SAFE_FREE(socket);
+ return tsk_null;
+ }
+ }
+ return socket;
+#endif
+}
+
+int tnet_tls_socket_connect(tnet_tls_socket_handle_t* self)
+{
+#if !HAVE_OPENSSL
+ TSK_DEBUG_ERROR("You MUST enable OpenSSL");
+ return -200;
+#else
+ int ret;
+ tnet_tls_socket_t* socket = self;
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if((ret = SSL_connect(socket->ssl)) != 1){
+ ret = SSL_get_error(socket->ssl, ret);
+ if(ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ || ret == SSL_ERROR_SYSCALL){
+ ret = 0; /* up to the caller to check that the socket is writable and valid */
+ }
+ else{
+ TSK_DEBUG_ERROR("SSL_connect failed [%d, %s]", ret, ERR_error_string(ERR_get_error(), tsk_null));
+ }
+ }
+ else{
+ ret = 0;
+ }
+
+ return ret;
+#endif
+}
+
+int tnet_tls_socket_accept(tnet_tls_socket_handle_t* self)
+{
+#if !HAVE_OPENSSL
+ TSK_DEBUG_ERROR("You MUST enable OpenSSL");
+ return -200;
+#else
+ int ret = -1;
+ tnet_tls_socket_t* socket = self;
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if((ret = SSL_accept(socket->ssl)) != 1){
+ ret = SSL_get_error(socket->ssl, ret);
+ if(ret == SSL_ERROR_WANT_READ){
+ int retval;
+ fd_set rfds;
+ while (1)
+ {
+ FD_ZERO(&rfds);
+ FD_SET(socket->fd, &rfds);
+ retval = select(socket->fd + 1, &rfds, NULL, NULL, NULL);
+ if (retval == -1){
+ TNET_PRINT_LAST_ERROR("select() failed");
+ }
+ else if (retval)
+ {
+ if (FD_ISSET(socket->fd, &rfds)){
+ ret = SSL_accept(socket->ssl);
+ ret = SSL_get_error(socket->ssl, ret);
+ if (ret == SSL_ERROR_WANT_READ){
+ continue;
+ }
+ else{
+ if(ret == SSL_ERROR_NONE){
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ TSK_DEBUG_ERROR("SSL_accept() failed with error code [%d, %s]", ret, ERR_error_string(ERR_get_error(), tsk_null));
+ return -3;
+ }
+
+ return 0;
+#endif
+}
+
+int tnet_tls_socket_write(tnet_tls_socket_handle_t* self, const void* data, tsk_size_t size)
+{
+#if !HAVE_OPENSSL
+ TSK_DEBUG_ERROR("You MUST enable OpenSSL");
+ return -200;
+#else
+ int ret = -1;
+ tnet_tls_socket_t* socket = self;
+ tsk_bool_t try_again = tsk_true, want_read, want_write;
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* Write */
+ tsk_safeobj_lock(socket);
+ while(((ret = SSL_write(socket->ssl, data, (int)size)) <= 0) && try_again){
+ ret = SSL_get_error(socket->ssl, ret);
+ want_read = (ret == SSL_ERROR_WANT_READ);
+ want_write = (ret == SSL_ERROR_WANT_WRITE);
+
+ if(want_write || want_read){
+ if(!(ret = tnet_sockfd_waitUntil(socket->fd, TNET_TLS_TIMEOUT, want_write))){
+ continue;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("SSL_write failed [%d, %s]", ret, ERR_error_string(ERR_get_error(), tsk_null));
+ ret = -3;
+ try_again = tsk_false;
+ }
+ }
+ tsk_safeobj_unlock(socket);
+
+ ret = (ret > 0) ? 0 : -3;
+ return ret;
+#endif
+}
+
+int tnet_tls_socket_recv(tnet_tls_socket_handle_t* self, void** data, tsk_size_t *size, tsk_bool_t *isEncrypted)
+{
+#if !HAVE_OPENSSL
+ TSK_DEBUG_ERROR("You MUST enable OpenSSL");
+ return -200;
+#else
+ int ret = -1;
+ tsk_size_t read = 0;
+ tsk_size_t to_read = *size;
+ int rcount = TNET_TLS_RETRY_COUNT;
+ tnet_tls_socket_t* socket = self;
+
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(socket);
+
+ *isEncrypted = SSL_is_init_finished(socket->ssl) ? tsk_false : tsk_true;
+
+ /* SSL handshake has completed? */
+ if(*isEncrypted){
+ char* buffer[1024];
+ if((ret = SSL_read(socket->ssl, buffer, sizeof(buffer))) <= 0){
+ ret = SSL_get_error(socket->ssl, ret);
+ if(ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ){
+ ret = 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("SSL_read failed [%d, %s]", ret, ERR_error_string(ERR_get_error(), tsk_null));
+ }
+ *size = 0;
+ }
+ else{
+ *size = ret;
+ ret = 0;
+ }
+
+ goto bail;
+ }
+
+ /* Read Application data */
+ssl_read:
+ if(rcount && ((ret = SSL_read(socket->ssl, (((uint8_t*)*data)+read), (int)to_read)) <= 0)){
+ ret = SSL_get_error(socket->ssl, ret);
+ if(ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ){
+ if(!(ret = tnet_sockfd_waitUntil(socket->fd, TNET_TLS_TIMEOUT, (ret == SSL_ERROR_WANT_WRITE)))){
+ rcount--;
+ goto ssl_read;
+ }
+ }
+ else if(SSL_ERROR_ZERO_RETURN){ /* connection closed: do nothing, the transport layer will be alerted. */
+ *size = 0;
+ ret = 0;
+ TSK_DEBUG_INFO("TLS connection closed.");
+ }
+ else{
+ TSK_DEBUG_ERROR("SSL_read failed [%d, %s]", ret, ERR_error_string(ERR_get_error(), tsk_null));
+ }
+ }
+ else if(ret >=0){
+ read += (tsk_size_t)ret;
+
+ if((ret = SSL_pending(socket->ssl)) > 0){
+ void *ptr;
+ to_read = ret;
+
+ if((ptr = tsk_realloc(*data, (read + to_read)))){
+ *data = ptr;
+ goto ssl_read;
+ }
+ }
+ }
+
+bail:
+ tsk_safeobj_unlock(socket);
+
+ if(read){
+ *size = read;
+ return 0;
+ }
+ else{
+ return ret;
+ }
+#endif
+}
+
+
+
+
+//=================================================================================================
+// TLS socket object definition
+//
+static tsk_object_t* tnet_tls_socket_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_tls_socket_t *socket = self;
+ if(socket){
+ tsk_safeobj_init(socket);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_tls_socket_dtor(tsk_object_t * self)
+{
+ tnet_tls_socket_t *socket = self;
+ if(socket){
+#if HAVE_OPENSSL
+ if(socket->ssl){
+ SSL_shutdown(socket->ssl);
+ SSL_free(socket->ssl);
+ }
+#endif
+ tsk_safeobj_deinit(socket);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_tls_socket_def_s =
+{
+ sizeof(tnet_tls_socket_t),
+ tnet_tls_socket_ctor,
+ tnet_tls_socket_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_tls_socket_def_t = &tnet_tls_socket_def_s;
+
+
diff --git a/tinyNET/src/tls/tnet_tls.h b/tinyNET/src/tls/tnet_tls.h
new file mode 100644
index 0000000..5e00ec8
--- /dev/null
+++ b/tinyNET/src/tls/tnet_tls.h
@@ -0,0 +1,64 @@
+/*
+* Copyright (C) 2010-2012 Mamadou Diop.
+* Copyright (C) 2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_tls.h
+ * @brief TLS utilitity functions, based on openssl.
+ */
+#ifndef TNET_TLS_H
+#define TNET_TLS_H
+
+#include "tinynet_config.h"
+#include "tnet_types.h"
+
+#if HAVE_OPENSSL
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# if !defined (HAVE_OPENSSL_DTLS_SRTP) /* try to guess if DTLS/SRTP is supported by ourself if not specified in CFLAGS */
+# if OPENSSL_VERSION_NUMBER >= 0x10001000L
+# define HAVE_OPENSSL_DTLS_SRTP 1
+# endif
+# endif
+# if !defined (HAVE_OPENSSL_DTLS) /* try to guess if DTLS is supported by ourself if not specified in CFLAGS */
+# if OPENSSL_VERSION_NUMBER >= 0x10000000L
+# define HAVE_OPENSSL_DTLS 1
+# endif
+# endif
+#endif
+
+TNET_BEGIN_DECLS
+
+typedef void tnet_tls_socket_handle_t;
+struct ssl_ctx_st;
+
+int tnet_tls_socket_connect(tnet_tls_socket_handle_t* self);
+int tnet_tls_socket_accept(tnet_tls_socket_handle_t* self);
+int tnet_tls_socket_write(tnet_tls_socket_handle_t* self, const void* data, tsk_size_t size);
+#define tnet_tls_socket_send(self, data, size) tnet_tls_socket_write(self, data, size)
+int tnet_tls_socket_recv(tnet_tls_socket_handle_t* self, void** data, tsk_size_t *size, tsk_bool_t *isEncrypted);
+
+TINYNET_API tsk_bool_t tnet_tls_is_supported();
+TINYNET_API tnet_tls_socket_handle_t* tnet_tls_socket_create(tnet_fd_t fd, struct ssl_ctx_st* ssl_ctx);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_tls_socket_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_TLS_H */
diff --git a/tinyNET/src/tnet.c b/tinyNET/src/tnet.c
new file mode 100644
index 0000000..25d763b
--- /dev/null
+++ b/tinyNET/src/tnet.c
@@ -0,0 +1,174 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet.c
+ * @brief Network stack.
+ */
+#include "tnet.h"
+#include "tnet_utils.h"
+#include "tnet_proxy_node_socks_plugin.h"
+#include "tnet_proxy_plugin.h"
+
+#include "tsk_time.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h> /* srand */
+
+#if HAVE_OPENSSL
+# include <openssl/ssl.h>
+#endif
+
+/** @mainpage tinyNET API Overview
+*
+* <h1>10 Sockets and Network Functions</h1>
+*
+* All network functions are part of tinyNET projects.<br>
+* You MUST call @ref tnet_startup() before using any network function (tnet_*). tnet_cleanup() is used to terminate use of network functions. <br>
+* The startup function will determine whether the host is a little-endian machine or not (at runtime).
+*
+* ======
+*
+* - @ref tnet_socket_group
+* - @ref tnet_utils_group
+* - @ref tnet_dhcp_group
+* - @ref tnet_dhcp6_group
+* - @ref tnet_dns_group
+* - @ref tnet_nat_group (@ref tnet_stun_group, @ref tnet_turn_group, ICE)
+*
+* ======
+*
+* <table>
+* <tr> <td><b>LDFLAGS</b></td> <td>-ltinySAK</td> </tr>
+* <tr> <td><b>CFLAGS</b></td> <td>-Isrc -ItinySAK/src</td> </tr>
+* </table>
+*
+*/
+static tsk_bool_t __tnet_started = tsk_false;
+tsk_bool_t tnet_isBigEndian = tsk_false;
+
+/**
+ * @fn tnet_startup
+ * This is probably the most important function. You MUST call this function to initialize the network stack before calling any <b>tnet_*</b> function. <br />
+ * On windows, this function will call <a target=_blank href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms742213(v=vs.85).aspx">WSAStartup</a>. <br />
+ * You MUST call @ref tnet_cleanup to cleanup the network stack if you no longer need to use networking function.
+ *
+ * @sa @ref tnet_cleanup.
+ * @return 0 if succeed and error code otherwise.
+**/
+int tnet_startup()
+{
+ int err = 0;
+ short word = 0x4321;
+
+ if (__tnet_started) {
+ goto bail;
+ }
+
+ if ((err = tnet_proxy_node_plugin_register(tnet_proxy_node_socks_plugin_def_t)) != 0) {
+ goto bail;
+ }
+
+ // rand()
+ srand((unsigned int) tsk_time_epoch());
+
+ // endianness
+ tnet_isBigEndian = ((*(int8_t *)&word) != 0x21);
+#if TNET_UNDER_WINDOWS
+ if (tnet_isBigEndian){
+ TSK_DEBUG_ERROR("Big endian on Windows machine. Is it right?");
+ }
+#endif
+ // Print messages regardless the debug level
+#if TNET_UNDER_WINDOWS_CE && (BUILD_TYPE_GE && SIN_CITY)
+# define PRINT_INFO TSK_DEBUG_INFO
+# define PRINT_ERROR TSK_DEBUG_ERROR
+#else
+# define PRINT_INFO(FMT, ...) fprintf(stdout, FMT "\n", ##__VA_ARGS__)
+# define PRINT_ERROR(FMT, ...) fprintf(stderr, FMT "\n", ##__VA_ARGS__)
+#endif
+
+#if TNET_UNDER_WINDOWS
+ {
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+ if (err != 0) {
+ PRINT_ERROR("WSAStartup failed with error: %d", err);
+ return -1;
+ }
+
+ if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
+ PRINT_ERROR("Could not find a usable version of Winsock.dll");
+ tnet_cleanup();
+ return -2;
+ }
+ else {
+ PRINT_INFO("The Winsock 2.2 dll was found okay");
+ }
+ }
+#endif /* TNET_UNDER_WINDOWS */
+
+#if HAVE_OPENSSL
+ PRINT_INFO("SSL is enabled :)");
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ SSL_load_error_strings();
+
+ PRINT_INFO("DTLS supported: %s", tnet_dtls_is_supported() ? "yes" : "no");
+ PRINT_INFO("DTLS-SRTP supported: %s", tnet_dtls_is_srtp_supported() ? "yes" : "no");
+#else
+ PRINT_ERROR("SSL is disabled :(");
+#endif
+
+ __tnet_started = tsk_true;
+
+bail:
+ return err;
+}
+
+
+/**
+ * Cleanup the network stack. <br />
+ * On windows, this function will call <a target=_blank href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms741549(v=vs.85).aspx">WSACleanup</a>. <br />
+ * @sa @ref tnet_startup.
+ * @return 0 if succeed and non-zero error code otherwise.
+**/
+int tnet_cleanup()
+{
+ if (!__tnet_started){
+ goto bail;
+ }
+
+ tnet_proxy_node_plugin_unregister(tnet_proxy_node_socks_plugin_def_t);
+
+#if TNET_UNDER_WINDOWS
+ __tnet_started = tsk_false;
+ return WSACleanup();
+#else
+ __tnet_started = tsk_false;
+#endif
+
+bail:
+ return 0;
+}
+
diff --git a/tinyNET/src/tnet.h b/tinyNET/src/tnet.h
new file mode 100644
index 0000000..92b8e53
--- /dev/null
+++ b/tinyNET/src/tnet.h
@@ -0,0 +1,45 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet.h
+ * @brief Network stack.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_TNET_H
+#define TNET_TNET_H
+
+#include "tinynet_config.h"
+
+#include "tsk_common.h"
+
+TNET_BEGIN_DECLS
+
+TINYNET_API int tnet_startup();
+TINYNET_API int tnet_cleanup();
+
+TNET_END_DECLS
+
+#endif /* TNET_TNET_H */
+
diff --git a/tinyNET/src/tnet_auth.c b/tinyNET/src/tnet_auth.c
new file mode 100644
index 0000000..941db1e
--- /dev/null
+++ b/tinyNET/src/tnet_auth.c
@@ -0,0 +1,30 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_auth.c
+ * @brief HTTP Authentication: Basic and Digest Access Authentication as per RFC 2617.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_auth.h"
diff --git a/tinyNET/src/tnet_auth.h b/tinyNET/src/tnet_auth.h
new file mode 100644
index 0000000..1f9642e
--- /dev/null
+++ b/tinyNET/src/tnet_auth.h
@@ -0,0 +1,39 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_auth.h
+ * @brief HTTP Authentication: Basic and Digest Access Authentication as per RFC 2617.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_AUTH_H
+#define TNET_AUTH_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+TNET_END_DECLS
+
+#endif /* TNET_AUTH_H */
diff --git a/tinyNET/src/tnet_endianness.c b/tinyNET/src/tnet_endianness.c
new file mode 100644
index 0000000..62f1708
--- /dev/null
+++ b/tinyNET/src/tnet_endianness.c
@@ -0,0 +1,98 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_endianness.c
+ * @brief Byte Ordering.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tnet_endianness.h"
+
+#include "tnet.h"
+
+extern tsk_bool_t tnet_isBigEndian;
+
+/** Converts a 16-bit value from host to TCP/IP network byte order (big-endian).
+* @param x The 16-bit (in host byte order) value to convert.
+* @retval @a x in TCP/IP network byte order.
+*/
+unsigned short tnet_htons(unsigned short x)
+{
+ if(tnet_is_BE()){
+ return x;
+ }
+ else{
+ return ((((uint16_t)(x) & 0xff00) >> 8) |
+ (((uint16_t)(x) & 0x00ff) << 8));
+ }
+}
+
+/* Memory alignment hack */
+unsigned short tnet_htons_2(const void* px)
+{
+ unsigned short y = TSK_TO_UINT16((const uint8_t*)px);
+ return tnet_htons(y);
+}
+
+/** Converts a 32-bit value from host to TCP/IP network byte order (big-endian).
+* @param x The 32-bit (in host byte order) value to convert.
+* @retval @a x in TCP/IP network byte order.
+*/
+unsigned long tnet_htonl(unsigned long x)
+{
+ if(tnet_is_BE()){
+ return x;
+ }
+ else{
+ return ((((uint32_t)(x) & 0xff000000) >> 24) | \
+ (((uint32_t)(x) & 0x00ff0000) >> 8) | \
+ (((uint32_t)(x) & 0x0000ff00) << 8) | \
+ (((uint32_t)(x) & 0x000000ff) << 24));
+ }
+}
+
+/* Memory alignment hack */
+unsigned long tnet_htonl_2(const void* px)
+{
+ unsigned long y = TSK_TO_UINT32((const uint8_t*)px);
+ return tnet_htonl(y);
+}
+
+/** Indicates whether we are on a Big Endian host or not.<br>
+* <b>IMPORTANT</b>: Before calling this function, you should initialize the network stack by using
+* @ref tnet_startup().
+* @retval @a tsk_true if the program is runnin on a Big Endian host and @a tsk_false otherwise.
+*/
+tsk_bool_t tnet_is_BE(){
+ /* If LITTLE_ENDIAN or BIG_ENDIAN macros have been defined in config.h ==> use them
+ * otherwise ==> dyn retrieve the endianness
+ */
+#if LITTLE_ENDIAN
+ return tsk_false;
+#elif BIG_ENDIAN
+ return tsk_true;
+#else
+ return tnet_isBigEndian;
+#endif
+}
diff --git a/tinyNET/src/tnet_endianness.h b/tinyNET/src/tnet_endianness.h
new file mode 100644
index 0000000..80a1232
--- /dev/null
+++ b/tinyNET/src/tnet_endianness.h
@@ -0,0 +1,58 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_endianness.h
+ * @brief Byte Ordering.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_ENDIANNESS_H
+#define TNET_ENDIANNESS_H
+
+#include "tinynet_config.h"
+
+#include "tsk_common.h" /* tsk_bool_t */
+
+TNET_BEGIN_DECLS
+
+#if defined(TINYNET_IMPORTS_IGNORE)
+#undef TNET_INLINE
+#define TNET_INLINE
+#endif
+
+TINYNET_API TNET_INLINE unsigned short tnet_htons(unsigned short x);
+TINYNET_API TNET_INLINE unsigned short tnet_htons_2(const void* px);
+TINYNET_API TNET_INLINE unsigned long tnet_htonl(unsigned long x);
+TINYNET_API TNET_INLINE unsigned long tnet_htonl_2(const void* px);
+TINYNET_API TNET_INLINE tsk_bool_t tnet_is_BE();
+
+#define tnet_ntohs(x) tnet_htons(x)
+#define tnet_ntohs_2(px) tnet_htons_2(px)
+#define tnet_ntohl(x) tnet_htonl(x)
+#define tnet_ntohl_2(px) tnet_htonl_2(px)
+
+TNET_END_DECLS
+
+#endif /*TNET_ENDIANNESS_H*/
+
diff --git a/tinyNET/src/tnet_hardwares.h b/tinyNET/src/tnet_hardwares.h
new file mode 100644
index 0000000..7d015b5
--- /dev/null
+++ b/tinyNET/src/tnet_hardwares.h
@@ -0,0 +1,64 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+/**@file tnet_hardwares.h
+ * @brief List of Hardware types as assigned by the IANA.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+
+#ifndef TNET_HARDWARES_H
+#define TNET_HARDWARES_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+/**
+* List of Hardware types as assigned by the IANA.
+* See RFC 1340, 826 and... for more information.
+*/
+typedef enum tnet_hardware_type_e
+{
+ tnet_htype_Ethernet_10Mb = 1, /**< Ethernet (10Mb) */
+ tnet_htype_Ethernet_3Mb = 2, /**< Experimental Ethernet (3Mb) */
+ tnet_htype_AX_25 = 3, /**< Amateur Radio AX.25 */
+ tnet_htype_Token_Ring = 4, /**< Proteon ProNET Token Ring */
+ tnet_htype_Chaos = 5, /**< Chaos */
+ tnet_htype_IEEE_802_Networks = 6, /**< IEEE 802 Networks */
+ tnet_htype_ARCNET = 7, /**< ARCNET */
+ tnet_htype_Hyperchannel = 8, /**< Hyperchannel */
+ tnet_htype_Lanstar = 9, /**< Lanstar */
+ tnet_htype_Autonet_Short_Address = 10, /**< Autonet Short Address */
+ tnet_htype_ALocalTalk = 11, /**< LocalTalk */
+ tnet_htype_LocalNet= 12, /**< LocalNet (IBM PCNet or SYTEK LocalNET) */
+ tnet_htype_Ultra_link = 13, /**< Ultra link */
+ tnet_htype_SMDS = 14, /**< SMDS */
+ tnet_htype_Frame_Relay = 15, /**< Frame Relay */
+ tnet_htype_ATM = 16, /**< Asynchronous Transmission Mode (ATM) */
+}
+tnet_hardware_type_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_HARDWARES_H */
diff --git a/tinyNET/src/tnet_nat.c b/tinyNET/src/tnet_nat.c
new file mode 100644
index 0000000..53a009a
--- /dev/null
+++ b/tinyNET/src/tnet_nat.c
@@ -0,0 +1,381 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_nat.c
+ * @brief NAT Traversal helper functions using STUN, TURN and ICE.
+ *
+ */
+#include "tnet_nat.h"
+#include "stun/tnet_stun_types.h"
+#include "stun/tnet_stun_utils.h"
+#include "stun/tnet_stun_pkt.h"
+#include "stun/tnet_stun_attr.h"
+#include "stun/tnet_stun_binding.h"
+
+#include "tnet_endianness.h"
+#include "tnet_socket.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+#include "tsk_debug.h"
+
+/**@defgroup tnet_nat_group NAT Traversal API (STUN, TURN and ICE).
+*/
+
+typedef struct tnet_nat_ctx_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_socket_type_t socket_type;
+
+ char* username; /**< The username to use to authenticate against the TURN/STUN server. */
+ char* password; /**< The password to use to authenticate against the TURN/STUN server. */
+
+ char* server_address; /**< TURN/STUN server address (could be FQDN or IP) */
+ tnet_port_t server_port; /**< TURN/STUN server port. */
+
+ uint16_t RTO; /**< Estimate of the round-trip time (RTT) in millisecond. */
+ uint16_t Rc; /**< Number of retransmissions for UDP in millisecond. */
+
+ unsigned use_dnsquery:1; /**< Indicates whether to use DNS SRV query to find the stun/turn ip address. */
+
+ tnet_stun_bindings_L_t *stun_bindings; /**< List of all STUN2 bindings associated to this context. */
+}
+tnet_nat_ctx_t;
+
+
+/**@ingroup tnet_nat_group
+* Creates new NAT context.
+*/
+struct tnet_nat_ctx_s* tnet_nat_context_create(tnet_socket_type_t socket_type, const char* pc_username, const char* pc_password)
+{
+ extern const tsk_object_def_t *tnet_nat_context_def_t;
+ struct tnet_nat_ctx_s* p_ctx;
+
+ if (!(p_ctx = tsk_object_new(tnet_nat_context_def_t)) || !(p_ctx->stun_bindings = tsk_list_create())) {
+ TSK_OBJECT_SAFE_FREE(p_ctx);
+ TSK_DEBUG_ERROR("Failed to create NAT context");
+ return tsk_null;
+ }
+
+ p_ctx->socket_type = socket_type;
+ p_ctx->username = tsk_strdup(pc_username);
+ p_ctx->password = tsk_strdup(pc_password);
+ p_ctx->server_port = kStunPortDefaultTcpUdp;
+ /* 7.2.1. Sending over UDP
+ In fixed-line access links, a value of 500 ms is RECOMMENDED.
+ */
+ p_ctx->RTO = kStunRTO;
+ /* 7.2.1. Sending over UDP
+ Rc SHOULD be configurable and SHOULD have a default of 7.
+ */
+ p_ctx->Rc = kStunRC;
+
+ return p_ctx;
+}
+
+/** Predicate function to find stun binding by id.
+ *
+ * @param [in,out] item The current list item.
+ * @param [in,out] id A pointer to the binding identifier.
+ *
+ * @return Zero if current list item hold a binding with the same id and -1 otherwise.
+**/
+int __pred_find_stun_binding(const tsk_list_item_t* item, const void* id)
+{
+ if(item) {
+ tnet_stun_binding_t *p_bind = item->data;
+ if (p_bind) {
+ tnet_stun_binding_id_t binding_id = *((tnet_stun_binding_id_t*)id);
+ return (p_bind->id == binding_id) ? 0 : -1;
+ }
+ }
+ return -1;
+}
+
+/**@ingroup tnet_nat_group
+ *
+ * Sets the address of the STUN/TURN server.
+ *
+ * @param [in,out] p_self The NAT context.
+ * @param [in,out] pc_server_address The address of server.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+**/
+int tnet_nat_set_server_address(struct tnet_nat_ctx_s* p_self, const char* pc_server_address)
+{
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_strupdate(&(p_self->server_address), pc_server_address);
+ return 0;
+}
+
+/**@ingroup tnet_nat_group
+ *
+ * Sets the address and port of the STUN/TURN server.
+ *
+ * @param [in,out] p_self The NAT context.
+ * @param [in,out] pc_server_address The address of server.
+ * @param u_server_port The server port.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+**/
+int tnet_nat_set_server(struct tnet_nat_ctx_s* p_self, const char* pc_server_address, tnet_port_t u_server_port)
+{
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_strupdate(&(p_self->server_address), pc_server_address);
+ p_self->server_port = u_server_port;
+ return 0;
+}
+
+/**@ingroup tnet_nat_group
+ *
+ * Creates and sends a STUN2 binding request to the STUN/TURN server in order to get the server reflexive
+ * address associated to this file descriptor (or socket). The caller should call @ref tnet_nat_stun_unbind to destroy the binding.
+ *
+ * @param [in,out] p_self The NAT context.
+ * @param localFD The local file descriptor (or socket) for which to get the reflexive server address.
+ *
+ * @return A valid binding id if succeed and @ref kStunBindingInvalidId otherwise. If the returned id is valid then
+ * the newly created binding will contain the server-reflexive address associated to the local file descriptor.
+ *
+ * @sa @ref tnet_nat_stun_unbind.
+**/
+tnet_stun_binding_id_t tnet_nat_stun_bind(const struct tnet_nat_ctx_s* p_self, const tnet_fd_t localFD)
+{
+ tnet_stun_binding_id_t id = kStunBindingInvalidId;
+ tnet_stun_binding_t *p_binding = tsk_null;
+ int ret;
+ if (!p_self || localFD == TNET_INVALID_FD) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ goto bail;
+ }
+ if ((ret = tnet_stun_binding_create(localFD, p_self->socket_type, p_self->server_address, p_self->server_port, p_self->username, p_self->password, &p_binding))) {
+ goto bail;
+ }
+ if ((ret = tnet_nat_stun_send_bind(p_self, p_binding))) {
+ goto bail;
+ }
+ id = p_binding->id;
+ tsk_list_push_back_data(p_self->stun_bindings, (void**)&p_binding);
+
+bail:
+ TSK_OBJECT_SAFE_FREE(p_binding);
+ return id;
+}
+
+
+/**@ingroup tnet_nat_group
+ * Internal function to send a STUN2 binding request over the network.
+ *
+ * @param [in,out] p_self The NAT context holding the user preferences.
+ * @param [in,out] p_binding The STUN binding object used to create the message to send.
+ *
+ * @return Zero if succeed and non-zero error code otherwise.
+**/
+int tnet_nat_stun_send_bind(const struct tnet_nat_ctx_s* pc_self, struct tnet_stun_binding_s *p_binding)
+{
+ int ret = -1;
+ tnet_stun_pkt_resp_t *p_pkt_resp = tsk_null;
+ tnet_stun_pkt_req_t *p_pkt_req = tsk_null;
+
+ if (!pc_self || !p_binding) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!TNET_SOCKET_TYPE_IS_DGRAM(p_binding->socket_type)) {
+ TSK_DEBUG_ERROR("Only DGRAM could be used for STUN transport");
+ return -2;
+ }
+
+ if ((ret = tnet_stun_binding_create_req(p_binding, &p_pkt_req))) {
+ goto bail;
+ }
+
+ /* RFC 5389 - 10.2.1.1. First Request
+ If the client has not completed a successful request/response
+ transaction with the server (as identified by hostname, if the DNS
+ procedures of Section 9 are used, else IP address if not), it SHOULD
+ omit the USERNAME, MESSAGE-INTEGRITY, REALM, and NONCE attributes.
+ In other words, the very first request is sent as if there were no
+ authentication or message integrity applied.
+ */
+stun_phase0: {
+ if ((ret = tnet_stun_utils_send_unreliably(p_binding->localFD, pc_self->RTO, pc_self->Rc, p_pkt_req, (struct sockaddr*)&p_binding->addr_server, &p_pkt_resp))) {
+ goto bail;
+ }
+
+ if (p_pkt_resp) {
+ if (TNET_STUN_PKT_RESP_IS_ERROR(p_pkt_resp)) {
+ uint16_t u_code;
+ if ((ret = tnet_stun_pkt_get_errorcode(p_pkt_resp, &u_code))) {
+ goto bail;
+ }
+ if (u_code == kStunErrCodeUnauthorized || u_code == kStunErrCodeStaleNonce) {
+ if (u_code == kStunErrCodeUnauthorized) {
+ // Make sure this is not an authentication failure (#2 401)
+ // Do not send another req to avoid endless messages
+ if ((tnet_stun_pkt_attr_exists(p_pkt_req, tnet_stun_attr_type_message_integrity))) { // already has a MESSAGE-INTEGRITY?
+ TSK_DEBUG_ERROR("STUN authentication failed");
+ goto bail;
+ }
+ }
+ if ((ret = tnet_stun_pkt_auth_prepare_2(p_pkt_req, p_binding->p_username, p_binding->p_password, p_pkt_resp))) {
+ goto bail;
+ }
+ // Try to send again now that authinfo is up2date
+ goto stun_phase0;
+ }
+ else if (u_code == kStunErrCodeUnknownAttributes) {
+ if((ret = tnet_stun_pkt_process_err420(p_pkt_req, p_pkt_resp))) {
+ goto bail;
+ }
+ // Try to send again now that authinfo is up2date
+ goto stun_phase0;
+ }
+ ret = -3;
+ }
+ else {
+ const tnet_stun_attr_address_t* pc_addr;
+ if ((ret = tnet_stun_pkt_attr_find_first(p_pkt_resp, tnet_stun_attr_type_xor_mapped_address, (const tnet_stun_attr_t**)&pc_addr)) == 0 && pc_addr) {
+ TSK_OBJECT_SAFE_FREE(p_binding->p_xmaddr);
+ p_binding->p_xmaddr = tsk_object_ref(TSK_OBJECT(pc_addr));
+ }
+ if ((ret = tnet_stun_pkt_attr_find_first(p_pkt_resp, tnet_stun_attr_type_mapped_address, (const tnet_stun_attr_t**)&pc_addr)) == 0 && pc_addr) {
+ TSK_OBJECT_SAFE_FREE(p_binding->p_maddr);
+ p_binding->p_maddr = tsk_object_ref(TSK_OBJECT(pc_addr));
+ }
+ }
+ }
+ }
+ /* END OF stun_phase0 */
+
+bail:
+ TSK_OBJECT_SAFE_FREE(p_pkt_resp);
+ TSK_OBJECT_SAFE_FREE(p_pkt_req);
+
+ return ret;
+}
+
+/**@ingroup tnet_nat_group
+ * Gets the server reflexive address associated to this STUN2 binding.
+ *
+ *
+ * @param [in,out] p_self The NAT context.
+ * @param id The id of the STUN2 binding conetxt (obtained using @ref tnet_nat_stun_bind) holding the server-reflexive address.
+ * @param [in,out] pp_ip The reflexive IP address. It is up the the caller to free the returned string
+ * @param [in,out] pu_port The reflexive port.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+**/
+int tnet_nat_stun_get_reflexive_address(const struct tnet_nat_ctx_s* p_self, tnet_stun_binding_id_t id, char** pp_ip, tnet_port_t *pu_port)
+{
+ const tsk_list_item_t* item;
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!pp_ip && !pu_port) {
+ return 0;
+ }
+
+ if ((item = tsk_list_find_item_by_pred(p_self->stun_bindings, __pred_find_stun_binding, &id)) && item->data) {
+ const tnet_stun_binding_t *pc_bind = (const tnet_stun_binding_t *)item->data;
+ const struct tnet_stun_attr_address_s *pc_addr = pc_bind->p_xmaddr ? pc_bind->p_xmaddr : pc_bind->p_maddr;
+ if (pc_addr) {
+ tnet_ip_t ip;
+ int ret;
+ if ((ret = tnet_stun_utils_inet_ntop((pc_addr->e_family == tnet_stun_address_family_ipv6), &pc_addr->address, &ip))) {
+ return ret;
+ }
+ if (pp_ip) {
+ tsk_strupdate(pp_ip, ip);
+ }
+ if (pu_port) {
+ *pu_port = pc_addr->u_port;
+ }
+ return 0;
+ }
+ }
+ return -2;
+}
+
+/**@ingroup tnet_nat_group
+ *
+ * Removes a STUN2 binding from the NAT context.
+ *
+ * @param [in,out] p_self The NAT context from which to remove the STUN2 binding.
+ * @param id The id of the STUN2 binding to remove.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+ *
+ *
+ * @sa @ref tnet_nat_stun_bind.
+**/
+int tnet_nat_stun_unbind(const struct tnet_nat_ctx_s* p_self, tnet_stun_binding_id_t id)
+{
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_list_remove_item_by_pred(p_self->stun_bindings, __pred_find_stun_binding, &id);
+ return 0;
+}
+
+
+//=================================================================================================
+// NAT CONTEXT object definition
+//
+static tsk_object_t* tnet_nat_context_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_nat_ctx_t *p_ctx = (tnet_nat_ctx_t*)self;
+ if (p_ctx) {
+ }
+ return self;
+}
+static tsk_object_t* tnet_nat_context_dtor(tsk_object_t * self)
+{
+ tnet_nat_ctx_t *p_ctx = (tnet_nat_ctx_t*)self;
+ if (p_ctx) {
+ TSK_FREE(p_ctx->username);
+ TSK_FREE(p_ctx->password);
+ TSK_FREE(p_ctx->server_address);
+
+ TSK_OBJECT_SAFE_FREE(p_ctx->stun_bindings);
+ TSK_DEBUG_INFO("*** NAT context destroyed ***");
+ }
+
+ return self;
+}
+static const tsk_object_def_t tnet_nat_context_def_s =
+{
+ sizeof(tnet_nat_ctx_t),
+ tnet_nat_context_ctor,
+ tnet_nat_context_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_nat_context_def_t = &tnet_nat_context_def_s;
diff --git a/tinyNET/src/tnet_nat.h b/tinyNET/src/tnet_nat.h
new file mode 100644
index 0000000..46d774f
--- /dev/null
+++ b/tinyNET/src/tnet_nat.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2010-2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+#ifndef TNET_NAT_H
+#define TNET_NAT_H
+
+#include "tinynet_config.h"
+#include "tnet_socket.h"
+
+#include "stun/tnet_stun_types.h"
+
+TNET_BEGIN_DECLS
+
+struct tnet_nat_ctx_s;
+struct tnet_stun_binding_s;
+enum tnet_socket_type_e;
+
+TINYNET_API int tnet_nat_set_server_address(struct tnet_nat_ctx_s* p_self, const char* pc_srv_addr);
+TINYNET_API int tnet_nat_set_server(struct tnet_nat_ctx_s* p_self, const char* pc_srv_addr, tnet_port_t u_srv_port);
+TINYNET_API tnet_stun_binding_id_t tnet_nat_stun_bind(const struct tnet_nat_ctx_s* p_self, const tnet_fd_t localFD);
+TINYNET_API int tnet_nat_stun_send_bind(const struct tnet_nat_ctx_s* pc_self, struct tnet_stun_binding_s *p_binding);
+TINYNET_API int tnet_nat_stun_get_reflexive_address(const struct tnet_nat_ctx_s* p_self, tnet_stun_binding_id_t id, char** pp_ip, tnet_port_t *pu_port);
+TINYNET_API int tnet_nat_stun_unbind(const struct tnet_nat_ctx_s* p_self, tnet_stun_binding_id_t id);
+TINYNET_API struct tnet_nat_ctx_s* tnet_nat_context_create(enum tnet_socket_type_e socket_type, const char* pc_username, const char* pc_password);
+
+TNET_END_DECLS
+
+#endif /* TNET_NAT_H */
diff --git a/tinyNET/src/tnet_poll.c b/tinyNET/src/tnet_poll.c
new file mode 100644
index 0000000..816f9c6
--- /dev/null
+++ b/tinyNET/src/tnet_poll.c
@@ -0,0 +1,109 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+#include "tnet_poll.h"
+
+#if USE_POLL && (!HAVE_POLL || !HAVE_POLL_H)
+
+/**
+ *
+ * @brief poll() method implementation for multiplexing network sockets.
+ *
+ * @param fds An array of pollfd structures.
+ * @param nfds The number of file descriptors set in fds[ ].
+ * @param timeout How long poll() should wait for an event to occur (in milliseconds).
+ *
+ * @return The number of elements in fdarray for which an revents member of the POLLFD structure is nonzero.
+ * If the the returned value if <0 this mean that error occurred.
+**/
+
+int tnet_poll(tnet_pollfd_t fds[ ], tnet_nfds_t nfds, int timeout)
+{
+ tsk_size_t i;
+ int ret;
+ int highest_fd = -1;
+
+ fd_set readfds;
+ fd_set writefds;
+ fd_set exceptfds;
+ struct timeval timetowait;
+
+ /*
+ * cleanup fd_sets
+ */
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&exceptfds);
+
+ /*
+ * set timeout
+ */
+ if(timeout >=0){
+ timetowait.tv_sec = (timeout/1000);
+ timetowait.tv_usec = (timeout%1000) * 1000;
+ }
+
+ /*
+ * add descriptors to the fd_sets
+ */
+ for(i = 0; i<nfds; i++){
+ if(fds[i].fd != TNET_INVALID_FD){
+ if(fds[i].events & TNET_POLLIN){
+ FD_SET(fds[i].fd, &readfds);
+ }
+ if(fds[i].events & TNET_POLLOUT){
+ FD_SET(fds[i].fd, &writefds);
+ }
+ if(fds[i].events & TNET_POLLPRI){
+ FD_SET(fds[i].fd, &exceptfds);
+ }
+ }
+
+ highest_fd = (highest_fd < fds[i].fd) ? fds[i].fd : highest_fd;
+ }
+
+ /*======================================
+ * select
+ */
+ if((ret = select(highest_fd + 1, &readfds, &writefds, &exceptfds, (timeout >=0) ? &timetowait : 0)) >= 0){
+ for(i = 0; i<nfds; i++){
+ if(fds[i].fd != TNET_INVALID_FD){
+ fds[i].revents = 0;
+
+ if(FD_ISSET(fds[i].fd, &readfds)){
+ fds[i].revents |= TNET_POLLIN;
+ }
+ if(FD_ISSET(fds[i].fd, &writefds)){
+ fds[i].revents |= TNET_POLLOUT;
+ }
+ if(FD_ISSET(fds[i].fd, &exceptfds)){
+ fds[i].revents |= TNET_POLLPRI;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+#endif /* TNET_USE_POLL */
+
+
diff --git a/tinyNET/src/tnet_poll.h b/tinyNET/src/tnet_poll.h
new file mode 100644
index 0000000..becd1c3
--- /dev/null
+++ b/tinyNET/src/tnet_poll.h
@@ -0,0 +1,92 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_poll.h
+ * @brief poll() method implementation for multiplexing network sockets.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_POLL_H
+#define TNET_POLL_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+#if USE_POLL
+
+#include "tnet_types.h"
+
+typedef unsigned long tnet_nfds_t;
+
+#if HAVE_POLL
+
+typedef struct pollfd tnet_pollfd_t;
+
+#define TNET_POLLRDNORM POLLRDNORM
+#define TNET_POLLRDBAND POLLRDBAND
+#define TNET_POLLIN POLLIN
+#define TNET_POLLPRI POLLPRI
+
+#define TNET_POLLWRNORM POLLWRNORM
+#define TNET_POLLOUT POLLOUT
+#define TNET_POLLWRBAND POLLWRBAND
+
+#define TNET_POLLERR POLLERR
+#define TNET_POLLHUP POLLHUP
+#define TNET_POLLNVAL POLLNVAL
+
+#if TNET_UNDER_WINDOWS
+# define tnet_poll WSAPoll
+#else
+# define tnet_poll poll
+#endif /* TNET_UNDER_WINDOWS */
+
+#else
+
+typedef struct tnet_pollfd_s
+{
+ tnet_fd_t fd;
+ short events;
+ short revents;
+}
+tnet_pollfd_t;
+
+#define TNET_POLLIN 0x0001 /* There is data to read */
+#define TNET_POLLPRI 0x0002 /* There is urgent data to read */
+#define TNET_POLLOUT 0x0004 /* Writing now will not block */
+#define TNET_POLLERR 0x0008 /* Error condition */
+#define TNET_POLLHUP 0x0010 /* Hung up */
+#define TNET_POLLNVAL 0x0020 /* Invalid request: fd not open */
+
+int tnet_poll(tnet_pollfd_t fds[ ], tnet_nfds_t nfds, int timeout);
+
+#endif /* HAVE_POLL */
+
+#endif /* TNET_USE_POLL */
+
+TNET_END_DECLS
+
+#endif /* TNET_POLL_H */
+
diff --git a/tinyNET/src/tnet_proto.h b/tinyNET/src/tnet_proto.h
new file mode 100644
index 0000000..ef7d89e
--- /dev/null
+++ b/tinyNET/src/tnet_proto.h
@@ -0,0 +1,196 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_proto.h
+ * @brief List of all assigned protocols as defined by the IANA (http://www.iana.org/assignments/protocol-numbers/).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TNET_PROTO_H
+#define TNET_PROTO_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+/**
+ * @enum tnet_proto_e
+ *
+ * @brief List of all assigned protocols as defined by the IANA
+ (http://www.iana.org/assignments/protocol-numbers/).
+**/
+typedef enum tnet_proto_e
+{
+ TNET_PROTO_HOPOPT = 0, /**< HOPOPT IPv6 Hop-by-Hop Option [RFC1883] */
+ TNET_PROTO_ICMP = 1, /**< ICMP Internet Control Message [RFC792] */
+ TNET_PROTO_IGMP = 2, /**< IGMP Internet Group Management [RFC1112] */
+ TNET_PROTO_GGP = 3, /**< GGP Gateway-to-Gateway [RFC823] */
+ TNET_PROTO_IP = 4, /**< IP IP in IP (encapsulation) [RFC2003] */
+ TNET_PROTO_ST = 5, /**< ST Stream [RFC1190][RFC1819] */
+ TNET_PROTO_TCP = 6, /**< TCP Transmission Control [RFC793] */
+ TNET_PROTO_CBT = 7, /**< CBT CBT [Ballardie] */
+ TNET_PROTO_EGP = 8, /**< EGP Exterior Gateway Protocol [RFC888][DLM1] */
+ TNET_PROTO_IGP = 9, /**< IGP any private interior gateway [IANA](used by Cisco for their IGRP) */
+ TNET_PROTO_BBN_RCC_MON = 10, /**< BBN-RCC-MON BBN RCC Monitoring [SGC] */
+ TNET_PROTO_NVP_II = 11, /**< NVP-II Network Voice Protocol [RFC741][SC3] */
+ TNET_PROTO_PUP = 12, /**< PUP PUP [PUP][XEROX] */
+ TNET_PROTO_ARGUS = 13, /**< ARGUS ARGUS [RWS4] */
+ TNET_PROTO_EMCON = 14, /**< EMCON EMCON [BN7] */
+ TNET_PROTO_XNET = 15, /**< XNET Cross Net Debugger [IEN158][JFH2] */
+ TNET_PROTO_CHAOS = 16, /**< CHAOS Chaos [NC3] */
+ TNET_PROTO_UDP = 17, /**< UDP User Datagram [RFC768][JBP] */
+ TNET_PROTO_MUX = 18, /**< MUX Multiplexing [IEN90][JBP] */
+ TNET_PROTO_DCN_MEAS = 19, /**< DCN-MEAS DCN Measurement Subsystems [DLM1] */
+ TNET_PROTO_HMP = 20, /**< HMP Host Monitoring [RFC869][RH6] */
+ TNET_PROTO_PRM = 21, /**< PRM Packet Radio Measurement [ZSU] */
+ TNET_PROTO_XNS_IDP = 22, /**< XNS-IDP XEROX NS IDP [ETHERNET][XEROX] */
+ TNET_PROTO_TRUNK_1 = 23, /**< TRUNK-1 Trunk-1 [BWB6] */
+ TNET_PROTO_TRUNK_2 = 24, /**< TRUNK-2 Trunk-2 [BWB6] */
+ TNET_PROTO_LEAF_1 = 25, /**< LEAF-1 Leaf-1 [BWB6] */
+ TNET_PROTO_LEAF_2 = 26, /**< LEAF-2 Leaf-2 [BWB6] */
+ TNET_PROTO_RDP = 27, /**< RDP Reliable Data Protocol [RFC908][RH6] */
+ TNET_PROTO_IRTP = 28, /**< IRTP Internet Reliable Transaction [RFC938][TXM] */
+ TNET_PROTO_ISO_TP4 = 29, /**< ISO-TP4 ISO Transport Protocol Class 4 [RFC905][RC77] */
+ TNET_PROTO_NETBLT = 30, /**< NETBLT Bulk Data Transfer Protocol [RFC969][DDC1] */
+ TNET_PROTO_MFE_NSP = 31, /**< MFE-NSP MFE Network Services Protocol [MFENET][BCH2] */
+ TNET_PROTO_MERIT_INP = 32, /**< MERIT-INP MERIT Internodal Protocol [HWB] */
+ TNET_PROTO_DCCP = 33, /**< DCCP Datagram Congestion Control Protocol [RFC4340] */
+ TNET_PROTO_3PC = 34, /**< 3PC Third Party Connect Protocol [SAF3] */
+ TNET_PROTO_IDPR = 35, /**< IDPR Inter-Domain Policy Routing Protocol [MXS1] */
+ TNET_PROTO_XTP = 36, /**< XTP XTP [GXC] */
+ TNET_PROTO_DDP = 37, /**< DDP Datagram Delivery Protocol [WXC] */
+ TNET_PROTO_IDPR_CMTP = 38, /**< IDPR-CMTP IDPR Control Message Transport Proto [MXS1] */
+ TNET_PROTO_TP_PP = 39, /**< TP++ TP++ Transport Protocol [DXF] */
+ TNET_PROTO_IL = 40, /**< IL IL Transport Protocol [Presotto] */
+ TNET_PROTO_IPv6 = 41, /**< IPv6 Ipv6 [Deering] */
+ TNET_PROTO_SDRP = 42, /**< SDRP Source Demand Routing Protocol [DXE1] */
+ TNET_PROTO_IPv6_Route = 43, /**< IPv6-Route Routing Header for IPv6 [Deering] */
+ TNET_PROTO_IPv6_Frag = 44, /**< IPv6-Frag Fragment Header for IPv6 [Deering] */
+ TNET_PROTO_IDRP = 45, /**< IDRP Inter-Domain Routing Protocol [Hares] */
+ TNET_PROTO_RSVP = 46, /**< RSVP Reservation Protocol [Braden] */
+ TNET_PROTO_GRE = 47, /**< GRE General Routing Encapsulation [Li] */
+ TNET_PROTO_DSR = 48, /**< DSR Dynamic Source Routing Protocol [RFC4728] */
+ TNET_PROTO_BNA = 49, /**< BNA BNA [Salamon] */
+ TNET_PROTO_ESP = 50, /**< ESP Encap Security Payload [RFC4303] */
+ TNET_PROTO_AH = 51, /**< AH Authentication Header [RFC4302] */
+ TNET_PROTO_I_NLSP = 52, /**< I-NLSP Integrated Net Layer Security TUBA [GLENN] */
+ TNET_PROTO_SWIPE = 53, /**< SWIPE IP with Encryption [JI6] */
+ TNET_PROTO_NARP = 54, /**< NARP NBMA Address Resolution Protocol [RFC1735] */
+ TNET_PROTO_MOBILE = 55, /**< MOBILE IP Mobility [Perkins] */
+ TNET_PROTO_TLSP = 56, /**< TLSP Transport Layer Security Protocol [Oberg] using Kryptonet key management */
+ TNET_PROTO_SKIP = 57, /**< SKIP SKIP [Markson] */
+ TNET_PROTO_IPv6_ICMP = 58, /**< IPv6-ICMP ICMP for IPv6 [RFC1883] */
+ TNET_PROTO_IPv6_NoNxt = 59, /**< IPv6-NoNxt No Next Header for IPv6 [RFC1883] */
+ TNET_PROTO_IPv6_Opts = 60, /**< IPv6-Opts Destination Options for IPv6 [RFC1883] */
+ TNET_PROTO_ANY_INTERNAL = 61, /**< any host internal protocol [IANA] */
+ TNET_PROTO_CFTP = 62, /**< CFTP CFTP [CFTP][HCF2] */
+ TNET_PROTO_ANY_LOCAL = 63, /**< any local network [IANA] */
+ TNET_PROTO_SAT_EXPAK = 64, /**< SAT-EXPAK SATNET and Backroom EXPAK [SHB] */
+ TNET_PROTO_KRYPTOLAN = 65, /**< KRYPTOLAN Kryptolan [PXL1] */
+ TNET_PROTO_RVD = 66, /**< RVD MIT Remote Virtual Disk Protocol [MBG] */
+ TNET_PROTO_IPPC = 67, /**< IPPC Internet Pluribus Packet Core [SHB] */
+ TNET_PROTO_ANY_DISTRIBUTED = 68, /**< any distributed file system [IANA] */
+ TNET_PROTO_SAT_MON = 69, /**< SAT-MON SATNET Monitoring [SHB] */
+ TNET_PROTO_VISA = 70, /**< VISA VISA Protocol [GXT1] */
+ TNET_PROTO_IPCV = 71, /**< IPCV Internet Packet Core Utility [SHB] */
+ TNET_PROTO_CPNX = 72, /**< CPNX Computer Protocol Network Executive [DXM2] */
+ TNET_PROTO_CPHB = 73, /**< CPHB Computer Protocol Heart Beat [DXM2] */
+ TNET_PROTO_WSN = 74, /**< WSN Wang Span Network [VXD] */
+ TNET_PROTO_PVP = 75, /**< PVP Packet Video Protocol [SC3] */
+ TNET_PROTO_BR_SAT_MON = 76, /**< BR-SAT-MON Backroom SATNET Monitoring [SHB] */
+ TNET_PROTO_SUN_ND = 77, /**< SUN-ND SUN ND PROTOCOL-Temporary [WM3] */
+ TNET_PROTO_WB_MON = 78, /**< WB-MON WIDEBAND Monitoring [SHB] */
+ TNET_PROTO_WB_EXPAK = 79, /**< WB-EXPAK WIDEBAND EXPAK [SHB] */
+ TNET_PROTO_ISO_IP = 80, /**< ISO-IP ISO Internet Protocol [MTR] */
+ TNET_PROTO_VMTP = 81, /**< VMTP VMTP [DRC3] */
+ TNET_PROTO_SECURE_VMTP = 82, /**< SECURE-VMTP SECURE-VMTP [DRC3] */
+ TNET_PROTO_VINES = 83, /**< VINES VINES [BXH] */
+ TNET_PROTO_TTP = 84, /**< TTP TTP [JXS] */
+ TNET_PROTO_NSFNET_IGP = 85, /**< NSFNET-IGP NSFNET-IGP [HWB] */
+ TNET_PROTO_DGP = 86, /**< DGP Dissimilar Gateway Protocol [DGP][ML109] */
+ TNET_PROTO_TCF = 87, /**< TCF TCF [GAL5] */
+ TNET_PROTO_EIGRP = 88, /**< EIGRP EIGRP [CISCO][GXS] */
+ TNET_PROTO_OSPFIGP = 89, /**< OSPFIGP OSPFIGP [RFC1583][JTM4] */
+ TNET_PROTO_Sprite_RPC = 90, /**< Sprite-RPC Sprite RPC Protocol [SPRITE][BXW] */
+ TNET_PROTO_LARP = 91, /**< LARP Locus Address Resolution Protocol [BXH] */
+ TNET_PROTO_MTP = 92, /**< MTP Multicast Transport Protocol [SXA] */
+ TNET_PROTO_AX25 = 93, /**< AX.25 AX.25 Frames [BK29] */
+ TNET_PROTO_IPIP = 94, /**< IPIP IP-within-IP Encapsulation Protocol [JI6] */
+ TNET_PROTO_MICP = 95, /**< MICP Mobile Internetworking Control Pro. [JI6] */
+ TNET_PROTO_SCC_SP = 96, /**< SCC-SP Semaphore Communications Sec. Pro. [HXH] */
+ TNET_PROTO_ETHERIP = 97, /**< ETHERIP Ethernet-within-IP Encapsulation [RFC3378] */
+ TNET_PROTO_ENCAP = 98, /**< ENCAP Encapsulation Header [RFC1241,RXB3] */
+ TNET_PROTO_ANY_PRIV_ENC = 99, /**< any private encryption scheme [IANA] */
+ TNET_PROTO_GMTP = 100, /**< GMTP GMTP [RXB5] */
+ TNET_PROTO_IFMP = 101, /**< IFMP Ipsilon Flow Management Protocol [Hinden] */
+ TNET_PROTO_PNNI = 102, /**< PNNI PNNI over IP [Callon] */
+ TNET_PROTO_PIM = 103, /**< PIM Protocol Independent Multicast [Farinacci] */
+ TNET_PROTO_ARIS = 104, /**< ARIS ARIS [Feldman] */
+ TNET_PROTO_SCPS = 105, /**< SCPS SCPS [Durst] */
+ TNET_PROTO_QNX = 106, /**< QNX QNX [Hunter] */
+ TNET_PROTO_AN = 107, /**< A/N Active Networks [Braden] */
+ TNET_PROTO_IPComp = 108, /**< IPComp IP Payload Compression Protocol [RFC2393] */
+ TNET_PROTO_SNP = 109, /**< SNP Sitara Networks Protocol [Sridhar] */
+ TNET_PROTO_Compaq_Peer = 110, /**< Compaq-Peer Compaq Peer Protocol [Volpe] */
+ TNET_PROTO_IPX_in_IP = 11, /**< IPX-in-IP IPX in IP [Lee] */
+ TNET_PROTO_VRRP = 112, /**< VRRP Virtual Router Redundancy Protocol [RFC3768][RFC-ietf-vrrp-unified-spec-05.txt] */
+ TNET_PROTO_PGM = 113, /**< PGM PGM Reliable Transport Protocol [Speakman] */
+ TNET_PROTO_ANY_ZERO_HOP = 114, /**< any 0-hop protocol [IANA] */
+ TNET_PROTO_L2TP = 115, /**< L2TP Layer Two Tunneling Protocol [Aboba] */
+ TNET_PROTO_DDX = 116, /**< DDX D-II Data Exchange (DDX) [Worley] */
+ TNET_PROTO_IATP = 117, /**< IATP Interactive Agent Transfer Protocol [Murphy] */
+ TNET_PROTO_STP = 118, /**< STP Schedule Transfer Protocol [JMP] */
+ TNET_PROTO_SRP = 119, /**< SRP SpectraLink Radio Protocol [Hamilton] */
+ TNET_PROTO_UTI = 120, /**< UTI UTI [Lothberg] */
+ TNET_PROTO_SMP = 121, /**< SMP Simple Message Protocol [Ekblad] */
+ TNET_PROTO_SM = 122, /**< SM SM [Crowcroft] */
+ TNET_PROTO_PTP = 123, /**< PTP Performance Transparency Protocol [Welzl] */
+ TNET_PROTO_ISIS = 124, /**< ISIS over IPv4 [Przygienda] */
+ TNET_PROTO_FIRE = 125, /**< FIRE [Partridge] */
+ TNET_PROTO_CRTP = 126, /**< CRTP Combat Radio Transport Protocol [Sautter] */
+ TNET_PROTO_CRUDP = 127, /**< CRUDP Combat Radio User Datagram [Sautter] */
+ TNET_PROTO_SSCOPMCE = 128, /**< SSCOPMCE [Waber] */
+ TNET_PROTO_IPLT = 129, /**< IPLT [Hollbach] */
+ TNET_PROTO_SPS = 130, /**< SPS Secure Packet Shield [McIntosh] */
+ TNET_PROTO_PIPE = 131, /**< PIPE Private IP Encapsulation within IP [Petri] */
+ TNET_PROTO_SCTP = 132, /**< SCTP Stream Control Transmission Protocol [Stewart] */
+ TNET_PROTO_FC = 133, /**< FC Fibre Channel [Rajagopal] */
+ TNET_PROTO_RSVP_E2E_IGNORE = 134, /**< RSVP-E2E-IGNORE [RFC3175] */
+ TNET_PROTO_Mobility_Header = 135, /**< Mobility Header [RFC3775] */
+ TNET_PROTO_UDPLite = 136, /**< UDPLite [RFC3828] */
+ TNET_PROTO_MPLS_in_IP = 137, /**< MPLS-in-IP [RFC4023] */
+ TNET_PROTO_manet = 138, /**< manet MANET Protocols [RFC5498] */
+ TNET_PROTO_HIP = 139, /**< HIP Host Identity Protocol [RFC5201] */
+ TNET_PROTO_Shim6 = 140, /**< Shim6 Shim6 Protocol [RFC5533] */
+ //TNET_PROTO_ = 141-252 Unassigned [IANA]
+ TNET_PROTO_EXP1 = 253, /**< Use for experimentation and testing [RFC3692] */
+ TNET_PROTO_EXP2 = 254, /**< Use for experimentation and testing [RFC3692] */
+ TNET_PROTO_Reserved = 255, /**< Reserved [IANA] */
+
+}
+tnet_proto_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_PROTO_H */
diff --git a/tinyNET/src/tnet_proxy_node_socks_plugin.c b/tinyNET/src/tnet_proxy_node_socks_plugin.c
new file mode 100644
index 0000000..e5f8d08
--- /dev/null
+++ b/tinyNET/src/tnet_proxy_node_socks_plugin.c
@@ -0,0 +1,917 @@
+/*
+ * Copyright (C) 2010-2015 Mamadou DIOP.
+ * Copyright (C) 2015 Doubango Telecom.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+
+// http://en.wikipedia.org/wiki/SOCKS
+// SOCKS Protocol Version 5: http://tools.ietf.org/html/rfc1928
+// Username/Password Authentication for SOCKS V5: https://www.ietf.org/rfc/rfc1929.txt
+// GSS-API Authentication Method for SOCKS Version 5: https://tools.ietf.org/html/rfc1961
+// SSPI/Kerberos Interoperability with GSSAPI: https://msdn.microsoft.com/en-us/library/ms995352.aspx
+// Mozilla issue: https://bugzilla.mozilla.org/show_bug.cgi?id=122752
+
+#include "tnet_proxy_node_socks_plugin.h"
+#include "tnet_proxy_plugin.h"
+#include "tnet_socket.h"
+#include "tnet_utils.h"
+#include "tnet_endianness.h"
+
+#include "tsk_safeobj.h"
+#include "tsk_buffer.h"
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#if TNET_UNDER_APPLE
+# if !defined(USING_CFSTREAM)
+# define USING_CFSTREAM 0 // Works with HTTP streams only :(
+# endif /* USING_CFSTREAM */
+#endif /* TNET_UNDER_APPLE */
+
+#if USING_CFSTREAM
+# import <CFNetwork/CFNetwork.h>
+# import <SystemConfiguration/SystemConfiguration.h>
+#endif /* TNET_UNDER_APPLE */
+
+#if HAVE_GSSAPI_H
+# if TNET_UNDER_APPLE
+# include <GSS/gssapi.h>
+# else
+# include <gssapi.h>
+# endif
+#endif /* HAVE_GSSAPI_H */
+
+#define kSocks4StatusGranted 0x5a
+
+#if !defined(TNET_SOCKS5_HAVE_AUTH_NONE)
+# define TNET_SOCKS5_HAVE_AUTH_NONE 1
+#endif /* TNET_SOCKS5_HAVE_AUTH_NONE */
+
+#if !defined(TNET_SOCKS5_HAVE_AUTH_USRPWD)
+# define TNET_SOCKS5_HAVE_AUTH_USRPWD 1
+#endif /* TNET_SOCKS5_HAVE_AUTH_USRPWD */
+
+#if !defined(TNET_SOCKS5_HAVE_AUTH_GSSAPI)
+# if HAVE_GSSAPI_H // TODO: Add Microsoft SSPI
+# define TNET_SOCKS5_HAVE_AUTH_GSSAPI 0
+# endif /* HAVE_GSSAPI_H */
+#endif /* TNET_SOCKS5_HAVE_AUTH_GSSAPI */
+
+#if !TNET_SOCKS5_HAVE_AUTH_NONE && !TNET_SOCKS5_HAVE_AUTH_USRPWD && !TNET_SOCKS5_HAVE_AUTH_GSSAPI
+# error "At least one Socks5 authentication method must be enabled"
+#endif
+
+#define kSocks5AuthMethodNone 0x00 // NO AUTHENTICATION REQUIRED
+#define kSocks5AuthMethodGSSAPI 0x01 // GSSAPI
+#define kSocks5AuthMethodUsrPwd 0x02 // USERNAME/PASSWORD
+
+typedef int socks5_auth_method_t;
+
+typedef enum socks5_state_e {
+ socks5_state_none,
+ socks5_state_greeting,
+ socks5_state_auth_req,
+ socks5_state_conn_req,
+ socks5_state_conn_accept,
+
+ socks5_state_error
+}
+socks5_state_t;
+
+typedef struct tnet_proxy_node_socks_plugin_s
+{
+ TNET_DECLARE_PROXY_NONE;
+
+ struct {
+ tsk_bool_t completed;
+ tsk_bool_t started;
+ tsk_buffer_t* buff;
+ uint8_t* pending_data_ptr;
+ tsk_size_t pending_data_len;
+
+ socks5_state_t socks5_state;
+ socks5_auth_method_t socks5_auth_method;
+#if TNET_SOCKS5_HAVE_AUTH_GSSAPI
+ struct {
+ gss_ctx_id_t ctx;
+ OM_uint32 status_minor;
+ OM_uint32 status_major;
+ gss_name_t server_name;
+ tsk_bool_t init_sec_complete;
+ }gss;
+#endif /* TNET_SOCKS5_HAVE_AUTH_GSSAPI */
+ } handshacking;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_proxy_node_socks_plugin_t;
+
+static const char* __socks5_state_to_string(socks5_state_t state);
+static const char* __socks5_method_to_string(socks5_auth_method_t method);
+#if TNET_SOCKS5_HAVE_AUTH_GSSAPI
+static int __socks5_gss_import_name(tnet_proxy_node_t* self);
+static int __socks5_gss_init_sec_context(tnet_proxy_node_t* self);
+static void __socks_gss_print_error(const char* info, OM_uint32 status_major, OM_uint32 status_minor);
+#endif /* TNET_SOCKS5_HAVE_AUTH_GSSAPI */
+
+static int _tnet_proxy_node_socks_plugin_configure(tnet_proxy_node_t* self, ...)
+{
+ tnet_proxy_node_socks_plugin_t* node = (tnet_proxy_node_socks_plugin_t*)self;
+ va_list ap;
+ int ret = 0;
+
+ // input parameters already checked by the caller
+
+ tsk_safeobj_lock(node);
+
+ // extract dst_host, dst_port, proxy_host, proxy_port, ipv6_enabled, ...
+ va_start(ap, self);
+ ret = tnet_proxy_node_configure_2(self, &ap);
+ va_end(ap);
+
+ tsk_safeobj_unlock(node);
+
+ return 0;
+}
+
+static int _tnet_proxy_node_socks_plugin_start_handshaking(tnet_proxy_node_t* self)
+{
+ tnet_proxy_node_socks_plugin_t* node = (tnet_proxy_node_socks_plugin_t*)self;
+ int ret = 0;
+
+ // input parameters already checked by the caller
+
+ tsk_safeobj_lock(node);
+ if (node->handshacking.started) {
+ TSK_DEBUG_ERROR("handshaking already started");
+ goto bail;
+ }
+ if (tsk_strnullORempty(self->dst_host) || !self->dst_port) {
+ TSK_DEBUG_ERROR("Invalid proxy host and/or port for socks server %s:%hu", self->proxy_host, self->proxy_port);
+ ret = -2;
+ goto bail;
+ }
+
+ // reset pending data
+ TSK_FREE(node->handshacking.pending_data_ptr);
+ node->handshacking.pending_data_len = 0;
+
+#if USING_CFSTREAM
+ if (tsk_strnullORempty(self->proxy_host) || !self->proxy_port) {
+ TSK_DEBUG_ERROR("Invalid proxy host and/or port for socks server %s:%hu", self->proxy_host, self->proxy_port);
+ ret = -2;
+ goto bail;
+ }
+ if (!self->cf_read_stream || !self->cf_write_stream) {
+ TSK_DEBUG_ERROR("Invalid CFStreams: read=%d write=%d", !!self->cf_read_stream, !!self->cf_write_stream);
+ ret = -3;
+ goto bail;
+ }
+
+ CFStringRef cfstrHost = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, self->proxy_host, kCFStringEncodingUTF8, NULL);
+ int intPort = (int)self->proxy_port;
+ CFNumberRef cfintPort = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &intPort);
+ CFDictionaryRef proxyDict = CFNetworkCopySystemProxySettings();
+ CFMutableDictionaryRef socksConfig = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, proxyDict);
+ CFDictionarySetValue(socksConfig, kCFStreamPropertySOCKSProxyHost, cfstrHost);
+ CFDictionarySetValue(socksConfig, kCFStreamPropertySOCKSProxyPort, cfintPort);
+ CFDictionarySetValue(socksConfig, kCFStreamPropertySOCKSVersion, self->type == tnet_proxy_type_socks4 ? kCFStreamSocketSOCKSVersion4 : kCFStreamSocketSOCKSVersion5);
+ if (!tsk_strnullORempty(self->login)) {
+ CFStringRef cfstrLogin = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, self->login, kCFStringEncodingUTF8, NULL);
+ CFDictionarySetValue(socksConfig, kCFStreamPropertySOCKSUser, cfstrLogin);
+ CFRelease(cfstrLogin);
+ }
+ if (!tsk_strnullORempty(self->password)) {
+ CFStringRef cfstrPassword = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, self->password, kCFStringEncodingUTF8, NULL);
+ CFDictionarySetValue(socksConfig, kCFStreamPropertySOCKSPassword, cfstrPassword);
+ CFRelease(cfstrPassword);
+ }
+
+ if (!CFReadStreamSetProperty(self->cf_read_stream, kCFStreamPropertySOCKSProxy, socksConfig)) {
+ CFStreamError error = CFReadStreamGetError(self->cf_read_stream);
+
+ TSK_DEBUG_INFO("CFReadStreamSetProperty(kCFStreamPropertySOCKSProxy) failed code=%d, domain=%ld", (int)error.error, error.domain);
+ ret = -4;
+ }
+ else if (!CFWriteStreamSetProperty(self->cf_write_stream, kCFStreamPropertySOCKSProxy, socksConfig)) {
+ CFStreamError error = CFWriteStreamGetError(self->cf_write_stream);
+ TSK_DEBUG_INFO("CFWriteStreamSetProperty(kCFStreamPropertySOCKSProxy) code=%d, domain=%ld", (int)error.error, error.domain);
+ ret = -5;
+ }
+
+ CFRelease(cfstrHost);
+ CFRelease(cfintPort);
+ CFRelease(socksConfig);
+ CFRelease(proxyDict);
+
+ node->handshacking.started = (ret == 0);
+ node->handshacking.completed = node->handshacking.started; // no handshaking data to send, up to the system
+#else
+ {
+ tsk_size_t size_to_reserve, userid_len = tsk_strlen(self->login), domain_len = 0;
+ if (self->type == tnet_proxy_type_socks4 || self->type == tnet_proxy_type_socks4a) {
+ size_to_reserve = 1 /* version number */
+ + 1 /* command code */
+ + 2 /* network byte order port number */
+ + 4 /* network byte order IP address */
+ + userid_len + 1 /* the user ID string, variable length, terminated with a null (0x00) */
+ ;
+ if (self->type == tnet_proxy_type_socks4a) {
+ domain_len = tsk_strlen(self->dst_host);
+ size_to_reserve += domain_len + 1/* the domain name of the host we want to contact, variable length, terminated with a null (0x00) */
+ ;
+ }
+ }
+ else { // SOCKS5
+ if (node->handshacking.socks5_state != socks5_state_none) {
+ TSK_DEBUG_ERROR("Socks5 handshaking state mut start at none");
+ ret = -6;
+ goto bail;
+ }
+ // Greeting
+ size_to_reserve = 1 /* version number */
+ + 1 /* number of authentication methods supported */
+#if TNET_SOCKS5_HAVE_AUTH_NONE
+ + 1
+#endif
+#if TNET_SOCKS5_HAVE_AUTH_USRPWD
+ + 1
+#endif
+#if TNET_SOCKS5_HAVE_AUTH_GSSAPI
+ + 1
+#endif
+ ;
+ }
+ node->handshacking.pending_data_ptr = (uint8_t*)tsk_realloc(node->handshacking.pending_data_ptr, size_to_reserve);
+ if (!node->handshacking.pending_data_ptr) {
+ TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", (unsigned)size_to_reserve);
+ node->handshacking.pending_data_len = 0;
+ ret = -5;
+ goto bail;
+ }
+ node->handshacking.pending_data_len = size_to_reserve;
+
+ if (self->type == tnet_proxy_type_socks4 || self->type == tnet_proxy_type_socks4a) {
+ node->handshacking.pending_data_ptr[0] = 0x04; // version number
+ node->handshacking.pending_data_ptr[1] = 0x01; // establish a TCP/IP stream connection (caller aldready check we're dealing with Streams)
+ node->handshacking.pending_data_ptr[2] = (self->dst_port >> 8) & 0xFF; // port, first byte
+ node->handshacking.pending_data_ptr[3] = self->dst_port & 0xFF; // port, second byte
+ if (self->type == tnet_proxy_type_socks4) {
+ struct sockaddr_storage addr;
+ // network byte order IPv4 address (SOCKS4 doesn't support hostnames)
+ if ((ret = tnet_sockaddr_init(self->dst_host, self->dst_port, self->socket.type, &addr)) != 0 || addr.ss_family != AF_INET) {
+ TSK_DEBUG_ERROR("tnet_sockaddr_init(%s, %d, %d) failed", self->dst_host, self->dst_port, self->socket.type);
+ ret = -6;
+ goto bail;
+ }
+ memcpy(&node->handshacking.pending_data_ptr[4], (void*)&((const struct sockaddr_in*)&addr)->sin_addr.s_addr, 4);
+ }
+ else {
+ // deliberate invalid IP address, 4 bytes, first three must be 0x00 and the last one must not be 0x00
+ node->handshacking.pending_data_ptr[4] = 0x00;
+ node->handshacking.pending_data_ptr[5] = 0x00;
+ node->handshacking.pending_data_ptr[6] = 0x00;
+ node->handshacking.pending_data_ptr[7] = 0x83; // non-zeo byte
+ }
+ // the user ID string, variable length, terminated with a null (0x00)
+ if (userid_len > 0) {
+ memcpy(&node->handshacking.pending_data_ptr[8], self->login, userid_len);
+ }
+ node->handshacking.pending_data_ptr[8 + userid_len] = 0x00;
+
+ // the domain name of the host we want to contact, variable length, terminated with a null (0x00)
+ if (self->type == tnet_proxy_type_socks4a) {
+ if (domain_len > 0) {
+ memcpy(&node->handshacking.pending_data_ptr[8 + userid_len + 1], self->dst_host, domain_len);
+ }
+ node->handshacking.pending_data_ptr[8 + userid_len + 1 + domain_len] = 0x00;
+ }
+ }
+ else { // SOCKS5
+ uint8_t* auths_ptr = &node->handshacking.pending_data_ptr[2];
+ node->handshacking.pending_data_ptr[0] = 0x05; // version number
+ node->handshacking.pending_data_ptr[1] = 0x00; // number of authentication methods supported
+#if TNET_SOCKS5_HAVE_AUTH_NONE
+ node->handshacking.pending_data_ptr[1] += 1;
+#endif
+#if TNET_SOCKS5_HAVE_AUTH_USRPWD
+ node->handshacking.pending_data_ptr[1] += 1;
+#endif
+#if TNET_SOCKS5_HAVE_AUTH_GSSAPI
+ node->handshacking.pending_data_ptr[1] += 1;
+#endif
+#if TNET_SOCKS5_HAVE_AUTH_GSSAPI
+ *auths_ptr++ = kSocks5AuthMethodGSSAPI;
+#endif
+#if TNET_SOCKS5_HAVE_AUTH_USRPWD
+ *auths_ptr++ = kSocks5AuthMethodUsrPwd;
+#endif
+#if TNET_SOCKS5_HAVE_AUTH_NONE
+ *auths_ptr++ = kSocks5AuthMethodNone;
+#endif
+ // change state from none to greeting
+ node->handshacking.socks5_state = socks5_state_greeting;
+ }
+ node->handshacking.started = tsk_true;
+ }
+#endif
+
+
+bail:
+ tsk_safeobj_unlock(node);
+ return ret;
+}
+
+static int _tnet_proxy_node_socks_plugin_set_handshaking_data(tnet_proxy_node_t* self, const void* data_ptr, tsk_size_t data_size)
+{
+ tnet_proxy_node_socks_plugin_t* node = (tnet_proxy_node_socks_plugin_t*)self;
+ int ret = 0;
+
+ // input parameters already checked by the caller
+
+ tsk_safeobj_lock(node);
+
+ if (!node->handshacking.started) {
+ TSK_DEBUG_ERROR("handshaking not started");
+ ret = -3;
+ goto bail;
+ }
+
+#if USING_CFSTREAM
+ TSK_DEBUG_ERROR("Up to CFStreams to handle handshaking");
+ ret = -2;
+ goto bail;
+#else
+ if (!node->handshacking.buff) {
+ if (!(node->handshacking.buff = tsk_buffer_create(data_ptr, data_size))) {
+ ret = -2;
+ goto bail;
+ }
+ }
+ else {
+ if ((ret = tsk_buffer_append(node->handshacking.buff, data_ptr, data_size)) != 0) {
+ goto bail;
+ }
+ }
+ if (self->type == tnet_proxy_type_socks4 || self->type == tnet_proxy_type_socks4a) {
+ static const tsk_size_t min_bytes_count = 8;
+ const uint8_t* buff = (const uint8_t*)node->handshacking.buff->data;
+ uint8_t status;
+ if (node->handshacking.buff->size < min_bytes_count) {
+ TSK_DEBUG_INFO("Not enough data in the SOCKS4/4a handshaking buffer yet");
+ goto bail;
+ }
+ status = buff[1];
+ TSK_DEBUG_INFO("SOCKS4/4a status = 0x%x", status);
+ if (status != kSocks4StatusGranted) { // status == granted ?
+ TSK_DEBUG_ERROR("SOCKS response from the server has status equal to 0x%x", status);
+ ret = -3;
+ goto bail;
+ }
+ // remove already parsed data
+ tsk_buffer_remove(node->handshacking.buff, 0, min_bytes_count);
+ // handshaking is done ?
+ node->handshacking.completed = (status == kSocks4StatusGranted);
+ }
+ else if (self->type == tnet_proxy_type_socks5) {
+ const uint8_t* buff = (const uint8_t*)node->handshacking.buff->data;
+ TSK_DEBUG_INFO("Socks5 state = %s", __socks5_state_to_string(node->handshacking.socks5_state));
+ if (node->handshacking.socks5_state == socks5_state_greeting) {
+ // response to greeting
+ if (node->handshacking.buff->size < 2/*1-byte version + 1-byte authentication method*/) {
+ TSK_DEBUG_INFO("Not enough data in the SOCKS5 handshaking buffer yet");
+ goto bail;
+ }
+ if (buff[0] != 0x05) {
+ TSK_DEBUG_ERROR("Invalid version (%d)", buff[0]);
+ ret = -3; goto bail;
+ }
+ if (buff[1] == kSocks5AuthMethodNone || buff[1] == kSocks5AuthMethodUsrPwd || buff[1] == kSocks5AuthMethodGSSAPI) {
+ node->handshacking.socks5_auth_method = (socks5_auth_method_t)buff[1];
+ TSK_DEBUG_INFO("Server selected Socks5 authentication method = %s", __socks5_method_to_string(node->handshacking.socks5_auth_method));
+ tsk_buffer_remove(node->handshacking.buff, 0, 2); // remove parsed bytes
+ if (node->handshacking.socks5_auth_method == kSocks5AuthMethodNone) {
+ node->handshacking.socks5_state = socks5_state_conn_req;
+ // FIXME:
+ TSK_DEBUG_ERROR("Not implemented yet");
+ ret = -3; goto bail;
+ }
+ else {
+ if (node->handshacking.socks5_auth_method == kSocks5AuthMethodUsrPwd) {
+ tsk_size_t userlen = tsk_strlen(self->login), pwdlen = tsk_strlen(self->password);
+ tsk_size_t size_to_reserve = 1 /* version number */
+ + 1 /* username length */
+ + userlen /* username */
+ + 1 /* password length */
+ + pwdlen;
+ node->handshacking.pending_data_ptr = (uint8_t*)tsk_realloc(node->handshacking.pending_data_ptr, size_to_reserve);
+ if (!node->handshacking.pending_data_ptr) {
+ TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", (unsigned)size_to_reserve);
+ node->handshacking.pending_data_len = 0;
+ ret = -5;
+ goto bail;
+ }
+ node->handshacking.pending_data_len = size_to_reserve;
+
+ node->handshacking.pending_data_ptr[0] = 0x01;
+ node->handshacking.pending_data_ptr[1] = (userlen & 0xFF);
+ if (userlen > 0) {
+ memcpy(&node->handshacking.pending_data_ptr[2], self->login, userlen);
+ }
+ node->handshacking.pending_data_ptr[2 + userlen] = (uint8_t)pwdlen;
+ if (pwdlen > 0) {
+ memcpy(&node->handshacking.pending_data_ptr[2 + userlen + 1], self->password, pwdlen);
+ }
+ node->handshacking.socks5_state = socks5_state_auth_req;
+ }
+ else if (node->handshacking.socks5_auth_method == kSocks5AuthMethodGSSAPI) {
+#if TNET_SOCKS5_HAVE_AUTH_GSSAPI
+ if ((ret = __socks5_gss_import_name(self))) {
+ TSK_DEBUG_ERROR("gss_import_name() failed");
+ goto bail;
+ }
+ if ((ret = __socks5_gss_init_sec_context(self))) {
+ TSK_DEBUG_ERROR("gss_import_name() failed");
+ goto bail;
+ }
+
+#else
+ TSK_DEBUG_ERROR("GSSAPI not supported");
+ ret = -3; goto bail;
+#endif
+ }
+ else {
+ TSK_DEBUG_ERROR("Not implemented yet");
+ ret = -3; goto bail;
+ }
+ }
+ }
+ else {
+ TSK_DEBUG_ERROR("Invalid authentication method (%d)", buff[1]);
+ ret = -3; goto bail;
+ }
+ }
+ else if (node->handshacking.socks5_state == socks5_state_auth_req) {
+ // response to authentication
+ if (node->handshacking.socks5_auth_method == kSocks5AuthMethodUsrPwd) {
+ if (node->handshacking.buff->size < 2/*1-byte version + 1-byte status code*/) {
+ TSK_DEBUG_INFO("Not enough data in the SOCKS5 handshaking buffer yet");
+ goto bail;
+ }
+ if (buff[0] != 0x1) {
+ TSK_DEBUG_ERROR("Invalid version :%d", buff[0]);
+ ret = -3; goto bail;
+ }
+ TSK_DEBUG_INFO("Socks5 authentication status code: %d", buff[1]);
+ if (buff[1] != 0x00) {
+ TSK_DEBUG_ERROR("Authentication failed with status code :%d", buff[1]);
+ ret = -3; goto bail;
+ }
+ tsk_buffer_remove(node->handshacking.buff, 0, 2); // remove parsed bytes
+ node->handshacking.socks5_state = socks5_state_conn_req;
+ }
+ else if (node->handshacking.socks5_auth_method == kSocks5AuthMethodGSSAPI) {
+ // FIXME:
+ TSK_DEBUG_ERROR("Not implemented yet");
+ ret = -3; goto bail;
+ }
+ else {
+ TSK_DEBUG_ERROR("Invalid authentication method (%d)", buff[1]);
+ ret = -3; goto bail;
+ }
+
+ // State changed from "auth_req" to "conn_req" : build connection request
+ if (node->handshacking.socks5_state == socks5_state_conn_req) {
+#define kAddrTypeIPv4 0x01
+#define kAddrTypeDomaineName 0x03
+#define kAddrTypeIPv6 0x04
+ struct sockaddr_storage addr;
+ tsk_bool_t is_ip = tsk_false; // ip or domain name
+ uint8_t addr_type = 0x00;
+ tsk_size_t dst_addr_len = 0, size_to_reserve = 1 /* version number */
+ + 1 /* command code */
+ + 1 /* reserved, must be 0x00 */
+ + 1 /* address type */
+ + 0 /* destination address (==to be computed later==) */
+ + 2 /* port number in a network byte order */
+ ;
+ if ((ret = tnet_sockaddr_init(self->dst_host, self->dst_port, self->socket.type, &addr)) != 0) {
+ TSK_DEBUG_WARN("tnet_sockaddr_init(%s, %d, %d) failed", self->dst_host, self->dst_port, self->socket.type);
+ // maybe DNS issue (e.g UDP blocked), do not exit, up to the server to resolve it
+ is_ip = tsk_false;
+ }
+ else {
+ tnet_ip_t ip = {0};
+ tnet_get_sockip((const struct sockaddr *)&addr, &ip);
+ is_ip = tsk_striequals(self->dst_host, ip);
+ }
+ if (is_ip) {
+ dst_addr_len = (addr.ss_family == AF_INET6) ? 16 : 4;
+ addr_type = (addr.ss_family == AF_INET6) ? kAddrTypeIPv6 : kAddrTypeIPv4;
+ }
+ else {
+ dst_addr_len = 1 /* length*/ + tsk_strlen(self->dst_host);
+ addr_type = kAddrTypeDomaineName;
+ }
+ size_to_reserve += dst_addr_len;
+ node->handshacking.pending_data_ptr = (uint8_t*)tsk_realloc(node->handshacking.pending_data_ptr, size_to_reserve);
+ if (!node->handshacking.pending_data_ptr) {
+ TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", (unsigned)size_to_reserve);
+ node->handshacking.pending_data_len = 0;
+ ret = -5; goto bail;
+ }
+ node->handshacking.pending_data_len = size_to_reserve;
+
+ node->handshacking.pending_data_ptr[0] = 0x05; // version number
+ node->handshacking.pending_data_ptr[1] = 0x01; // establish a TCP/IP stream connection
+ node->handshacking.pending_data_ptr[2] = 0x00; // reserved, must be 0x00
+ node->handshacking.pending_data_ptr[3] = addr_type;
+ if (addr_type == kAddrTypeIPv4) {
+ memcpy(&node->handshacking.pending_data_ptr[4], (void*)&((const struct sockaddr_in*)&addr)->sin_addr.s_addr, 4);
+ }
+ else if (addr_type == kAddrTypeIPv6) {
+ memcpy(&node->handshacking.pending_data_ptr[4], (void*)&((const struct sockaddr_in6*)&addr)->sin6_addr, 16);
+ }
+ else { // DomaineName
+ node->handshacking.pending_data_ptr[4] = (uint8_t)(dst_addr_len - 1);/* length */;
+ memcpy(&node->handshacking.pending_data_ptr[5], self->dst_host, (dst_addr_len - 1));
+ }
+ node->handshacking.pending_data_ptr[4 + dst_addr_len] = (self->dst_port >> 8) & 0xFF;
+ node->handshacking.pending_data_ptr[4 + dst_addr_len + 1] = (self->dst_port & 0xFF);
+ }
+ }
+ else if (node->handshacking.socks5_state == socks5_state_conn_req) {
+ // response to connection request
+ if (node->handshacking.buff->size < 2/*1-byte version + 1-byte status*/) {
+ TSK_DEBUG_INFO("Not enough data in the SOCKS5 handshaking buffer yet");
+ goto bail;
+ }
+ if (buff[0] != 0x05) {
+ TSK_DEBUG_ERROR("Invalid version (%d)", buff[0]);
+ ret = -3; goto bail;
+ }
+ TSK_DEBUG_INFO("Socks5 connection request status code: %d", buff[1]);
+ if (buff[1] != 0x00) {
+ TSK_DEBUG_ERROR("Socks5 connection request failed with status code :%d", buff[1]);
+ ret = -3; goto bail;
+ }
+ tsk_buffer_remove(node->handshacking.buff, 0, 2); // remove parsed bytes
+ node->handshacking.socks5_state = socks5_state_conn_accept;
+ node->handshacking.completed = tsk_true;
+ }
+ else if (node->handshacking.socks5_state == socks5_state_conn_accept) {
+ TSK_DEBUG_INFO("Socks5 connection accepted");
+ // nothing else to do
+ }
+ else {
+ // FIXME:
+ TSK_DEBUG_ERROR("Not implemented yet");
+ ret = -3;
+ goto bail;
+ }
+ }
+ else {
+ TSK_DEBUG_ERROR("Invalid proxy type:%d", self->type);
+ ret = -3;
+ goto bail;
+ }
+#endif
+
+bail:
+ if (ret != 0) {
+ if (self->type == tnet_proxy_type_socks5) {
+ node->handshacking.socks5_state = socks5_state_error;
+ }
+ }
+ tsk_safeobj_unlock(node);
+ return ret;
+}
+
+static int _tnet_proxy_node_socks_plugin_get_handshaking_pending_data(tnet_proxy_node_t* self, void** data_pptr, tsk_size_t* data_psize)
+{
+ tnet_proxy_node_socks_plugin_t* node = (tnet_proxy_node_socks_plugin_t*)self;
+ int ret = -1;
+
+ // input parameters already checked by the caller
+
+ tsk_safeobj_lock(node);
+
+#if USING_CFSTREAM
+ *data_psize = 0; // no pending data
+ ret = 0;
+#else
+ if (node->handshacking.pending_data_ptr && node->handshacking.pending_data_len > 0) {
+ if ((*data_pptr = tsk_realloc(*data_pptr, node->handshacking.pending_data_len))) {
+ memcpy(*data_pptr, node->handshacking.pending_data_ptr, (tsk_size_t) node->handshacking.pending_data_len);
+ *data_psize = node->handshacking.pending_data_len;
+ ret = 0;
+ }
+ // reset the pending data. Up to the caller to hold the returned data and send it as many as required (e.g. when using unreliable transport)
+ TSK_FREE(node->handshacking.pending_data_ptr);
+ node->handshacking.pending_data_len = 0;
+ }
+#endif
+
+ tsk_safeobj_unlock(node);
+ return ret;
+}
+
+static int _tnet_proxy_node_socks_plugin_get_handshaking_completed(tnet_proxy_node_t* self, tsk_bool_t* completed)
+{
+ tnet_proxy_node_socks_plugin_t* node = (tnet_proxy_node_socks_plugin_t*)self;
+ int ret = 0;
+
+ // input parameters already checked by the caller
+
+ tsk_safeobj_lock(node);
+ *completed = node->handshacking.completed;
+ tsk_safeobj_unlock(node);
+ return ret;
+}
+
+static const char* __socks5_state_to_string(socks5_state_t state)
+{
+ switch (state) {
+ case socks5_state_none: return "none";
+ case socks5_state_greeting: return "greeting";
+ case socks5_state_auth_req: return "auth_req";
+ case socks5_state_conn_req: return "conn_req";
+ case socks5_state_conn_accept: return "conn_accept";
+ case socks5_state_error: return "error";
+ default: return "unknown";
+ }
+}
+
+static const char* __socks5_method_to_string(socks5_auth_method_t method)
+{
+ switch (method) {
+ case kSocks5AuthMethodNone: return "none";
+ case kSocks5AuthMethodGSSAPI: return "gssapi";
+ case kSocks5AuthMethodUsrPwd: return "usr/pwd";
+ default: return "unknown";
+ }
+}
+
+#if TNET_SOCKS5_HAVE_AUTH_GSSAPI
+
+// rfc1961 - 3.1 Preparation
+static int __socks5_gss_import_name(tnet_proxy_node_t* self)
+{
+ int i, ret = 0;
+ tnet_proxy_node_socks_plugin_t* node = (tnet_proxy_node_socks_plugin_t*)self;
+ gss_buffer_desc input_name_buffer = GSS_C_EMPTY_BUFFER;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ // reset context
+ node->handshacking.gss.ctx = GSS_C_NO_CONTEXT;
+ // reset pending handshaking data
+ TSK_FREE(node->handshacking.pending_data_ptr);
+ node->handshacking.pending_data_len = 0;
+
+ /*
+ For example, when using Kerberos V5 naming, the imported name may be
+ of the form "SERVICE:socks@socks_server_hostname" where
+ "socks_server_hostname" is the fully qualified host name of the
+ server with all letters in lower case.
+ */
+ input_name_buffer.length = tsk_sprintf((char**)&input_name_buffer.value, "SERVICE:socks@%s", self->proxy_host);
+ for (i = 0; i < input_name_buffer.length; ++i) {
+ ((char*)input_name_buffer.value)[i] = tolower(((char*)input_name_buffer.value)[i]);
+ }
+
+ /*
+ The client should call gss_import_name to obtain an internal
+ representation of the server name. For maximal portability the
+ default name_type GSS_C_NULL_OID should be used to specify the
+ default name space, and the input name_string should treated by the
+ client's code as an opaque name-space specific input.
+ */
+ node->handshacking.gss.status_major = gss_import_name(&node->handshacking.gss.status_minor, &input_name_buffer, GSS_C_NULL_OID, &node->handshacking.gss.server_name);
+ TSK_DEBUG_INFO("gss_import_name(%.*s, GSS_C_NULL_OID): minor_status = %u, major_status = %u", (int)input_name_buffer.length, (const char*)input_name_buffer.value, node->handshacking.gss.status_minor, node->handshacking.gss.status_major);
+ if (node->handshacking.gss.status_major != GSS_S_COMPLETE) {
+ __socks_gss_print_error("gss_import_name failed", node->handshacking.gss.status_major, node->handshacking.gss.status_minor);
+ ret = -2; goto bail;
+ }
+ /* debug */{
+ gss_OID output_name_type;
+ gss_buffer_desc output_name = GSS_C_EMPTY_BUFFER;
+ node->handshacking.gss.status_major = gss_display_name(&node->handshacking.gss.status_minor,
+ node->handshacking.gss.server_name,
+ &output_name,
+ &output_name_type);
+ TSK_DEBUG_INFO("gss_display_name(%.*s): minor_status = %u, major_status = %u, output = %.*s", (int)input_name_buffer.length, (const char*)input_name_buffer.value, node->handshacking.gss.status_minor, node->handshacking.gss.status_major, (int)output_name.length, (const char*)output_name.value);
+ node->handshacking.gss.status_major = gss_release_buffer(&node->handshacking.gss.status_minor, &output_name);
+ }
+
+bail:
+ gss_release_buffer(&node->handshacking.gss.status_minor, &input_name_buffer);
+ return 0;
+}
+
+// 3.2 Client Context Establishment
+// 3.3 Client Context Establishment Major Status codes
+static int __socks5_gss_init_sec_context(tnet_proxy_node_t* self)
+{
+ int ret = 0;
+ OM_uint32 req_flags;
+ tnet_proxy_node_socks_plugin_t* node = (tnet_proxy_node_socks_plugin_t*)self;
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER, *input_token_ptr = GSS_C_NO_BUFFER;
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+
+/*
+ +------+------+------+.......................+
+ + ver | mtyp | len | token |
+ +------+------+------+.......................+
+ + 0x01 | 0x01 | 0x02 | up to 2^16 - 1 octets |
+ +------+------+------+.......................+
+*/
+#define kTokenMsgHdrLongLen 4 // with "len" field
+#define kTokenMsgHdrShortLen 2 // without "len" field
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (node->handshacking.buff && node->handshacking.buff->size >= kTokenMsgHdrShortLen) {
+ const uint8_t* buff = (const uint8_t*)node->handshacking.buff->data;
+ if (buff[1] == kSocks5AuthMethodGSSAPI) {
+ if (node->handshacking.buff->size >= kTokenMsgHdrLongLen) {
+ uint16_t len = ((buff[2] << 8) & 0x00FF) | (buff[3] & 0xFF);
+ if (len >= kTokenMsgHdrLongLen + node->handshacking.buff->size) {
+ input_token.value = (void*) (buff + kTokenMsgHdrLongLen);
+ input_token.length = (size_t)len;
+ input_token_ptr = &input_token;
+ TSK_DEBUG_INFO("GSS Input token: ver=%d, mtyp=%d, len=%d", buff[0], buff[1], len);
+ }
+ }
+ }
+ else {
+ TSK_DEBUG_ERROR("GSS invalid mtyp(%u)", buff[1]);
+ ret = -5; goto bail;
+ }
+ }
+
+ req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_DELEG_FLAG;
+ // However, GSS_C_SEQUENCE_FLAG should only be passed in for TCP-based clients, not for UDP-based clients.
+ if (TNET_SOCKET_TYPE_IS_STREAM(self->socket.type)) {
+ req_flags |= GSS_C_SEQUENCE_FLAG;
+ }
+
+ node->handshacking.gss.status_major = gss_delete_sec_context(&node->handshacking.gss.status_minor, &node->handshacking.gss.ctx, NULL);
+
+ node->handshacking.gss.ctx = GSS_C_NO_CONTEXT;
+ node->handshacking.gss.status_major = gss_init_sec_context(&node->handshacking.gss.status_minor,
+ GSS_C_NO_CREDENTIAL, // GSS_C_NO_CREDENTIAL into cred_handle to specify the default credential (for initiator usage)
+ &node->handshacking.gss.ctx,
+ node->handshacking.gss.server_name,
+ GSS_C_NULL_OID, // GSS_C_NULL_OID into mech_type to specify the default mechanism
+ req_flags,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ input_token_ptr,
+ tsk_null,
+ &output_token,
+ tsk_null,
+ tsk_null);
+
+
+ // Only "GSS_S_COMPLETE" and "GSS_S_CONTINUE_NEEDED" are acceptable
+ if (node->handshacking.gss.status_major != GSS_S_COMPLETE && node->handshacking.gss.status_major != GSS_S_CONTINUE_NEEDED) {
+ __socks_gss_print_error("gss_init_sec_context failed", node->handshacking.gss.status_major, node->handshacking.gss.status_minor);
+ ret = -2; goto bail;
+ }
+
+ // reset pending handshaking data
+ TSK_FREE(node->handshacking.pending_data_ptr);
+ node->handshacking.pending_data_len = 0;
+
+ if (output_token.length > 0 && output_token.value) {
+ node->handshacking.pending_data_len = kTokenMsgHdrLongLen + output_token.length;
+ node->handshacking.pending_data_ptr = tsk_realloc(node->handshacking.pending_data_ptr, node->handshacking.pending_data_len);
+ if (!node->handshacking.pending_data_ptr) {
+ TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", (unsigned)node->handshacking.pending_data_len);
+ node->handshacking.pending_data_len = 0;
+ ret = -3;
+ goto bail;
+ }
+ node->handshacking.pending_data_ptr[0] = 0x01;
+ node->handshacking.pending_data_ptr[1] = kSocks5AuthMethodGSSAPI;
+ node->handshacking.pending_data_ptr[2] = ((output_token.length >> 8) & 0xFF);
+ node->handshacking.pending_data_ptr[3] = output_token.length & 0xFF;
+ memcpy(&node->handshacking.pending_data_ptr[4], output_token.value, output_token.length);
+ }
+
+ if (input_token.length > 0) {
+ tsk_buffer_remove(node->handshacking.buff, 0, kTokenMsgHdrLongLen + input_token.length);
+ }
+
+ // update "init_sec_complete"
+ node->handshacking.gss.init_sec_complete = (ret == 0) && (node->handshacking.gss.status_major == GSS_S_COMPLETE);
+
+bail:
+ return ret;
+}
+
+static void __socks_gss_print_error(const char* info, OM_uint32 status_major, OM_uint32 status_minor)
+{
+ OM_uint32 m1, m2, s1, s2;
+ gss_buffer_desc out1 = {.value = tsk_null, .length = 0}, out2 = {.value = tsk_null, .length = 0};
+
+ // print the error
+ m1 = 0, s1 = 0;
+ gss_display_status(&s1, status_major, GSS_C_GSS_CODE, GSS_C_NULL_OID, &m1, &out1);
+ m2 = 0, s2 = 0;
+ gss_display_status(&s2, status_minor, GSS_C_MECH_CODE, GSS_C_NULL_OID, &m2, &out2);
+ TSK_DEBUG_ERROR("%s (status_major=%u, status_minor=%u): GSS_C_GSS_CODE(%u, %s), GSS_C_MECH_CODE(%u, %s)",
+ info,
+ status_major, status_minor,
+ s1, (const char*)out1.value, s2, (const char*)out2.value);
+ gss_release_buffer(&s1, &out1);
+ gss_release_buffer(&s2, &out2);
+}
+
+#endif /* TNET_SOCKS5_HAVE_AUTH_GSSAPI */
+
+/* constructor */
+static tsk_object_t* tnet_proxy_node_socks_plugin_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_proxy_node_socks_plugin_t *node = self;
+ if (node) {
+ /* init base */
+ tnet_proxy_node_init(TNET_PROXY_NODE(node));
+ /* init self */
+ tsk_safeobj_init(node);
+#if TNET_SOCKS5_HAVE_AUTH_GSSAPI
+ node->handshacking.gss.server_name = GSS_C_NO_NAME;
+ node->handshacking.gss.ctx = GSS_C_NO_CONTEXT;
+#endif
+ TSK_DEBUG_INFO("Create SOCKS(4/4a/5) proxy node");
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tnet_proxy_node_socks_plugin_dtor(tsk_object_t * self)
+{
+ tnet_proxy_node_socks_plugin_t *node = self;
+ if (node) {
+ /* deinit base */
+ tnet_proxy_node_deinit(TNET_PROXY_NODE(node));
+ /* deinit self */
+ TSK_FREE(node->handshacking.pending_data_ptr);
+ TSK_OBJECT_SAFE_FREE(node->handshacking.buff);
+#if TNET_SOCKS5_HAVE_AUTH_GSSAPI
+ gss_release_name(&node->handshacking.gss.status_minor, &node->handshacking.gss.server_name);
+ if (node->handshacking.gss.ctx != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context(&node->handshacking.gss.status_minor, &node->handshacking.gss.ctx, GSS_C_NO_BUFFER);
+ }
+#endif /* TNET_SOCKS5_HAVE_AUTH_GSSAPI */
+ tsk_safeobj_deinit(node);
+
+ TSK_DEBUG_INFO("*** Socks(4/4a/5) proxy node destroyed ***");
+ }
+ return self;
+}
+
+/* object definition */
+static const tsk_object_def_t thttp_proxy_node_def_s =
+{
+ sizeof(tnet_proxy_node_socks_plugin_t),
+ tnet_proxy_node_socks_plugin_ctor,
+ tnet_proxy_node_socks_plugin_dtor,
+ tsk_null,
+};
+/* plugin definition*/
+static const struct tnet_proxy_node_plugin_def_s tnet_proxy_node_socks_plugin_def_s =
+{
+ &thttp_proxy_node_def_s,
+
+ (tnet_proxy_type_socks4 | tnet_proxy_type_socks4a | tnet_proxy_type_socks5),
+
+ "SOCKS(4/4a/5) proxy node plugin",
+
+ _tnet_proxy_node_socks_plugin_configure,
+ _tnet_proxy_node_socks_plugin_start_handshaking,
+ _tnet_proxy_node_socks_plugin_set_handshaking_data,
+ _tnet_proxy_node_socks_plugin_get_handshaking_pending_data,
+ _tnet_proxy_node_socks_plugin_get_handshaking_completed
+};
+const struct tnet_proxy_node_plugin_def_s *tnet_proxy_node_socks_plugin_def_t = &tnet_proxy_node_socks_plugin_def_s;
diff --git a/tinyNET/src/tnet_proxy_node_socks_plugin.h b/tinyNET/src/tnet_proxy_node_socks_plugin.h
new file mode 100644
index 0000000..d6f942c
--- /dev/null
+++ b/tinyNET/src/tnet_proxy_node_socks_plugin.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010-2015 Mamadou DIOP.
+ * Copyright (C) 2015 Doubango Telecom.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+
+#if !defined(TNET_PROXY_SOCKS_PLUGIN_H)
+#define TNET_PROXY_SOCKS_PLUGIN_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+TINYNET_GEXTERN const struct tnet_proxy_node_plugin_def_s* tnet_proxy_node_socks_plugin_def_t;
+
+TNET_BEGIN_DECLS
+
+#endif /* defined(TNET_PROXY_SOCKS_PLUGIN_H) */
+
diff --git a/tinyNET/src/tnet_proxy_plugin.c b/tinyNET/src/tnet_proxy_plugin.c
new file mode 100644
index 0000000..dbcd143
--- /dev/null
+++ b/tinyNET/src/tnet_proxy_plugin.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2010-2015 Mamadou DIOP.
+ * Copyright (C) 2015 Doubango Telecom.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+#include "tnet_proxy_plugin.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#if !defined(TNET_PROXY_NODE_MAX_PLUGINS)
+# define TNET_PROXY_NODE_MAX_PLUGINS 10
+#endif
+
+const tnet_proxy_node_plugin_def_t* __tnet_proxy_node_plugins[TNET_PROXY_NODE_MAX_PLUGINS] = {0};
+
+
+tsk_bool_t tnet_proxy_node_is_nettransport_supported(enum tnet_proxy_type_e proxy_type, enum tnet_socket_type_e socket_type)
+{
+ switch (proxy_type) {
+ case tnet_proxy_type_http:
+ case tnet_proxy_type_https:
+ return TNET_SOCKET_TYPE_IS_STREAM(socket_type);
+
+ case tnet_proxy_type_socks4:
+ case tnet_proxy_type_socks4a:
+ return TNET_SOCKET_TYPE_IS_STREAM(socket_type) && TNET_SOCKET_TYPE_IS_IPV4(socket_type);
+ case tnet_proxy_type_socks5: // SOCKS5 adds support for UDP and IPv6
+ return TNET_SOCKET_TYPE_IS_STREAM(socket_type) || TNET_SOCKET_TYPE_IS_DGRAM(socket_type);// for now we don't support socks for UDP (just like a browser)
+ default:
+ return tsk_false;
+ }
+}
+
+int tnet_proxy_node_init(tnet_proxy_node_t* self)
+{
+ if (self) {
+ self->socket.fd = TNET_INVALID_FD;
+ self->socket.type = tnet_socket_type_invalid;
+ }
+ return 0;
+}
+
+int tnet_proxy_node_configure(tnet_proxy_node_t* self, ...)
+{
+ va_list ap;
+ int ret = 0;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ va_start(ap, self);
+ ret = tnet_proxy_node_configure_2(self, &ap);
+ va_end(ap);
+ return ret;
+}
+
+int tnet_proxy_node_configure_2(tnet_proxy_node_t* self, va_list* app)
+{
+ int ret = 0;
+ tnet_proxy_node_param_type_t ptype;
+
+ if (!self || !app) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ while ((ptype = va_arg(*app, tnet_proxy_node_param_type_t)) != tnet_proxy_node_param_type_null) {
+ switch (ptype) {
+ case tnet_proxy_node_param_type_destination_address:
+ case tnet_proxy_node_param_type_proxy_address: {
+ // (const char*)(HOST_STR), (int)(PORT_INT)
+ const char* HOST_STR = va_arg(*app, const char*);
+ int PORT_INT = va_arg(*app, int);
+ if (PORT_INT < 1 || PORT_INT > 0xFFF) {
+ TSK_DEBUG_ERROR("Invalid value for port number: %d", PORT_INT);
+ ret = -3;
+ goto bail;
+ }
+ if (ptype == tnet_proxy_node_param_type_destination_address) {
+ tsk_strupdate(&self->dst_host, HOST_STR);
+ self->dst_port = (tnet_port_t)PORT_INT;
+ }
+ else {
+ tsk_strupdate(&self->proxy_host, HOST_STR);
+ self->proxy_port = (tnet_port_t)PORT_INT;
+ }
+ break;
+ }
+ case tnet_proxy_node_param_type_ipv6: {
+ /* (tsk_bool_t)(IPV6_BOOL) */
+ self->ipv6 = va_arg(*app, tsk_bool_t);
+ break;
+ }
+ case tnet_proxy_node_param_type_credentials: {
+ /* (const char*)(LOGIN_STR), (const char*)(PASSWORD_STR) */
+ const char* LOGIN_STR = va_arg(*app, const char*);
+ const char* PASSWORD_STR = va_arg(*app, const char*);
+ tsk_strupdate(&self->login, LOGIN_STR);
+ tsk_strupdate(&self->password, PASSWORD_STR);
+ break;
+ }
+ case tnet_proxy_node_param_type_socket: {
+ /* (tnet_fd_t)(FD_FD), (enum tnet_socket_type_e)(type) */
+ self->socket.fd = va_arg(*app, tnet_fd_t);
+ self->socket.type = va_arg(*app, enum tnet_socket_type_e);
+ break;
+ }
+#if TNET_UNDER_APPLE
+ case tnet_proxy_node_param_type_cfstreams: {
+ /* (CFReadStreamRef)(READ_CFSTREAM), (CFWriteStreamRef)(WRITE_CFSTREAM) */
+ CFReadStreamRef READ_CFSTREAM = va_arg(*app, CFReadStreamRef);
+ CFWriteStreamRef WRITE_CFSTREAM = va_arg(*app, CFWriteStreamRef);
+ if (self->cf_read_stream) CFRelease(self->cf_read_stream), self->cf_read_stream = tsk_null;
+ if (self->cf_write_stream) CFRelease(self->cf_write_stream), self->cf_write_stream = tsk_null;
+ if (READ_CFSTREAM) self->cf_read_stream = (CFReadStreamRef)CFRetain(READ_CFSTREAM);
+ if (WRITE_CFSTREAM) self->cf_write_stream = (CFWriteStreamRef)CFRetain(WRITE_CFSTREAM);
+ break;
+ }
+#endif /* TNET_UNDER_APPLE */
+ default: {
+ TSK_DEBUG_ERROR("%d not valid param type", ptype);
+ ret = -2;
+ goto bail;
+ }
+ }
+ }
+
+bail:
+ return ret;
+}
+
+int tnet_proxy_node_start_handshaking(tnet_proxy_node_t* self)
+{
+ if (!self || !self->plugin || !self->plugin->start_handshaking) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return self->plugin->start_handshaking(self);
+}
+
+int tnet_proxy_node_set_handshaking_data(tnet_proxy_node_t* self, const void* data_ptr, tsk_size_t data_size)
+{
+ if (!self || !data_ptr || !data_size || !self->plugin || !self->plugin->set_handshaking_data) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return self->plugin->set_handshaking_data(self, data_ptr, data_size);
+}
+
+int tnet_proxy_node_get_handshaking_pending_data(tnet_proxy_node_t* self, void** data_pptr, tsk_size_t* data_psize)
+{
+ if (!self || !data_pptr || !data_psize || !self->plugin || !self->plugin->get_handshaking_pending_data) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return self->plugin->get_handshaking_pending_data(self, data_pptr, data_psize);
+}
+
+int tnet_proxy_node_get_handshaking_completed(tnet_proxy_node_t* self, tsk_bool_t* completed)
+{
+ if (!self || !completed || !self->plugin || !self->plugin->get_handshaking_completed) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return self->plugin->get_handshaking_completed(self, completed);
+}
+
+int tnet_proxy_node_deinit(tnet_proxy_node_t* self)
+{
+ if (self) {
+ TSK_FREE(self->dst_host);
+ TSK_FREE(self->proxy_host);
+ TSK_FREE(self->login);
+ TSK_FREE(self->password);
+#if TNET_UNDER_APPLE
+ if (self->cf_read_stream) {
+ CFRelease(self->cf_read_stream), self->cf_read_stream = tsk_null;
+ }
+ if (self->cf_write_stream) {
+ CFRelease(self->cf_write_stream), self->cf_write_stream = tsk_null;
+ }
+#endif
+ }
+ return 0;
+}
+
+int tnet_proxy_node_plugin_register(const tnet_proxy_node_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ if (!plugin || tsk_strnullORempty(plugin->desc)) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* add or replace the plugin */
+ for (i = 0; i<TNET_PROXY_NODE_MAX_PLUGINS; i++) {
+ if (!__tnet_proxy_node_plugins[i] || (__tnet_proxy_node_plugins[i] == plugin)){
+ __tnet_proxy_node_plugins[i] = plugin;
+ TSK_DEBUG_INFO("Register network proxy node plugin: %s", plugin->desc);
+ return 0;
+ }
+ }
+
+ TSK_DEBUG_ERROR("There are already %d network proxy node plugins.", TNET_PROXY_NODE_MAX_PLUGINS);
+ return -2;
+}
+
+int tnet_proxy_node_plugin_unregister(const tnet_proxy_node_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+ if (!plugin) {
+ TSK_DEBUG_ERROR("Invalid Parameter");
+ return -1;
+ }
+
+ /* find the plugin to unregister */
+ for (i = 0; i<TNET_PROXY_NODE_MAX_PLUGINS && __tnet_proxy_node_plugins[i]; i++) {
+ if (__tnet_proxy_node_plugins[i] == plugin) {
+ TSK_DEBUG_INFO("UnRegister network proxy node plugin: %s", plugin->desc);
+ __tnet_proxy_node_plugins[i] = tsk_null;
+ found = tsk_true;
+ break;
+ }
+ }
+
+ /* compact */
+ if (found) {
+ for (; i<(TNET_PROXY_NODE_MAX_PLUGINS - 1); i++) {
+ if (__tnet_proxy_node_plugins[i+1]) {
+ __tnet_proxy_node_plugins[i] = __tnet_proxy_node_plugins[i+1];
+ }
+ else {
+ break;
+ }
+ }
+ __tnet_proxy_node_plugins[i] = tsk_null;
+ }
+ return (found ? 0 : -2);
+}
+
+tsk_size_t tnet_proxy_node_plugin_registry_count()
+{
+ tsk_size_t count;
+ for(count = 0;
+ count < TNET_PROXY_NODE_MAX_PLUGINS && __tnet_proxy_node_plugins[count];
+ ++count) ;
+ return count;
+}
+
+tnet_proxy_node_t* tnet_proxy_node_create(enum tnet_proxy_type_e type)
+{
+ tsk_size_t i;
+ tnet_proxy_node_t* node = tsk_null;
+ for (i = 0; i<TNET_PROXY_NODE_MAX_PLUGINS && __tnet_proxy_node_plugins[i]; i++) {
+ if ((__tnet_proxy_node_plugins[i]->type & type) == type) {
+ if ((node = tsk_object_new(__tnet_proxy_node_plugins[i]->objdef))) {
+ node->type = type;
+ node->plugin = __tnet_proxy_node_plugins[i];
+ break;
+ }
+ }
+ }
+ return node;
+} \ No newline at end of file
diff --git a/tinyNET/src/tnet_proxy_plugin.h b/tinyNET/src/tnet_proxy_plugin.h
new file mode 100644
index 0000000..0a247bc
--- /dev/null
+++ b/tinyNET/src/tnet_proxy_plugin.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010-2015 Mamadou DIOP.
+ * Copyright (C) 2015 Doubango Telecom.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+#if !defined(TNET_PROXY_PLUGIN_H)
+#define TNET_PROXY_PLUGIN_H
+
+#include "tinynet_config.h"
+#include "tnet_types.h"
+#include "tnet_socket.h"
+
+#include "tsk_list.h"
+
+#if TNET_UNDER_APPLE
+# import <CFNetwork/CFNetwork.h>
+#endif /* TNET_UNDER_APPLE */
+
+TNET_BEGIN_DECLS
+
+typedef struct tnet_proxy_node_s {
+ TSK_DECLARE_OBJECT;
+
+ enum tnet_proxy_type_e type;
+ tsk_bool_t ipv6;
+ char* dst_host;
+ tnet_port_t dst_port;
+ char* proxy_host;
+ tnet_port_t proxy_port;
+ char* login;
+ char* password;
+ struct {
+ tnet_fd_t fd;
+ tnet_socket_type_t type;
+ } socket;
+#if TNET_UNDER_APPLE
+ CFReadStreamRef cf_read_stream;
+ CFWriteStreamRef cf_write_stream;
+#endif /* TNET_UNDER_APPLE */
+
+ const struct tnet_proxy_node_plugin_def_s* plugin;
+}
+tnet_proxy_node_t;
+
+#define TNET_PROXY_NODE(self) ((tnet_proxy_node_t*)(self))
+#define TNET_DECLARE_PROXY_NONE tnet_proxy_node_t __node__
+
+typedef enum tnet_proxy_node_param_type_e
+{
+ tnet_proxy_node_param_type_null = 0,
+ tnet_proxy_node_param_type_destination_address,
+ tnet_proxy_node_param_type_proxy_address,
+ tnet_proxy_node_param_type_ipv6,
+ tnet_proxy_node_param_type_credentials,
+ tnet_proxy_node_param_type_socket,
+#if TNET_UNDER_APPLE
+ tnet_proxy_node_param_type_cfstreams,
+#endif
+}
+tnet_proxy_node_param_type_t;
+#define TNET_PROXY_NODE_SET_NULL() tnet_proxy_node_param_type_null
+#define TNET_PROXY_SET_DEST_ADDRESS(HOST_STR, PORT_INT) tnet_proxy_node_param_type_destination_address, (const char*)(HOST_STR), (int)(PORT_INT)
+#define TNET_PROXY_SET_PROXY_ADDRESS(HOST_STR, PORT_INT) tnet_proxy_node_param_type_proxy_address, (const char*)(HOST_STR), (int)(PORT_INT)
+#define TNET_PROXY_NODE_SET_IPV6(IPV6_BOOL) tnet_proxy_node_param_type_ipv6, (tsk_bool_t)(IPV6_BOOL)
+#define TNET_PROXY_SET_CREDENTIALS(LOGIN_STR, PASSWORD_STR) tnet_proxy_node_param_type_credentials, (const char*)(LOGIN_STR), (const char*)(PASSWORD_STR)
+#define TNET_PROXY_SET_SOCKET(FD_FD, type) tnet_proxy_node_param_type_socket, (tnet_fd_t)(FD_FD), (enum tnet_socket_type_e)(type)
+
+#if TNET_UNDER_APPLE
+# define TNET_PROXY_SET_CFSTREAM(READ_CFSTREAM, WRITE_CFSTREAM) tnet_proxy_node_param_type_cfstreams, (CFReadStreamRef)(READ_CFSTREAM), (CFWriteStreamRef)(WRITE_CFSTREAM)
+#endif /* TNET_UNDER_APPLE */
+
+/** Virtual table used to define a proxy node plugin */
+typedef struct tnet_proxy_node_plugin_def_s
+{
+ //! object definition used to create an instance of the plugin
+ const tsk_object_def_t* objdef;
+
+ //! plugin type
+ enum tnet_proxy_type_e type;
+
+ //! full description (usefull for debugging)
+ const char* desc;
+
+ int (* configure) (tnet_proxy_node_t* self, ...);
+ int (* start_handshaking) (tnet_proxy_node_t* self);
+ int (* set_handshaking_data) (tnet_proxy_node_t* self, const void* data_ptr, tsk_size_t data_size);
+ int (* get_handshaking_pending_data) (tnet_proxy_node_t* self, void** data_pptr, tsk_size_t* data_psize);
+ int (* get_handshaking_completed) (tnet_proxy_node_t* self, tsk_bool_t* completed);
+}
+tnet_proxy_node_plugin_def_t;
+
+TINYNET_API tsk_bool_t tnet_proxy_node_is_nettransport_supported(enum tnet_proxy_type_e proxy_type, enum tnet_socket_type_e socket_type);
+TINYNET_API int tnet_proxy_node_init(tnet_proxy_node_t* self);
+TINYNET_API int tnet_proxy_node_configure(tnet_proxy_node_t* self, ...);
+TINYNET_API int tnet_proxy_node_configure_2(tnet_proxy_node_t* self, va_list* app);
+TINYNET_API int tnet_proxy_node_start_handshaking(tnet_proxy_node_t* self);
+TINYNET_API int tnet_proxy_node_set_handshaking_data(tnet_proxy_node_t* self, const void* data_ptr, tsk_size_t data_size);
+TINYNET_API int tnet_proxy_node_get_handshaking_pending_data(tnet_proxy_node_t* self, void** data_pptr, tsk_size_t* data_psize);
+TINYNET_API int tnet_proxy_node_get_handshaking_completed(tnet_proxy_node_t* self, tsk_bool_t* completed);
+TINYNET_API int tnet_proxy_node_deinit(tnet_proxy_node_t* self);
+
+TINYNET_API int tnet_proxy_node_plugin_register(const tnet_proxy_node_plugin_def_t* plugin);
+TINYNET_API int tnet_proxy_node_plugin_unregister(const tnet_proxy_node_plugin_def_t* plugin);
+TINYNET_API tsk_size_t tnet_proxy_node_plugin_registry_count();
+TINYNET_API tnet_proxy_node_t* tnet_proxy_node_create(enum tnet_proxy_type_e type);
+
+TNET_END_DECLS
+
+#endif /* TNET_PROXY_PLUGIN_H */
+
diff --git a/tinyNET/src/tnet_proxydetect.c b/tinyNET/src/tnet_proxydetect.c
new file mode 100644
index 0000000..162985c
--- /dev/null
+++ b/tinyNET/src/tnet_proxydetect.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2010-2015 Mamadou DIOP.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+#include "tnet_proxydetect.h"
+#include "tnet_utils.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+/* "tnet_proxyinfo_t" object definition */
+static tsk_object_t* _tnet_proxyinfo_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_proxyinfo_t *info = (tnet_proxyinfo_t *)self;
+ if (info) {
+
+ }
+ return self;
+}
+static tsk_object_t* _tnet_proxyinfo_dtor(tsk_object_t * self)
+{
+ tnet_proxyinfo_t *info = (tnet_proxyinfo_t *)self;
+ if (info){
+ TSK_FREE(info->autoconfig_url);
+ TSK_FREE(info->bypass_list);
+ TSK_FREE(info->hostname);
+ TSK_FREE(info->username);
+ TSK_FREE(info->password);
+ }
+
+ return self;
+}
+static const tsk_object_def_t tnet_proxyinfo_def_s =
+{
+ sizeof(tnet_proxyinfo_t),
+ _tnet_proxyinfo_ctor,
+ _tnet_proxyinfo_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_proxyinfo_def_t = &tnet_proxyinfo_def_s;
+
+tnet_proxyinfo_t* tnet_proxyinfo_create()
+{
+ tnet_proxyinfo_t* info = tsk_object_new(tnet_proxyinfo_def_t);
+ if (!info) {
+ TSK_DEBUG_ERROR("Failed to creatr 'tnet_proxyinfo_t' instance");
+ return info;
+ }
+
+ return info;
+}
+
+
+
+/******** Windows ************/
+#if TNET_UNDER_WINDOWS && !TNET_UNDER_WINDOWS_RT && !TNET_UNDER_WINDOWS_CE
+# include <Windows.h>
+# include <winhttp.h>
+
+tnet_proxyinfo_t* tnet_proxydetect_get_info(const char* url, tnet_socket_type_t socket_type, tsk_bool_t long_operation)
+{
+ TSK_DEBUG_WARN("Proxy detection not supported on your OS");
+ return tsk_null;
+}
+
+/******** iOS and OSX ************/
+#elif TNET_UNDER_APPLE
+
+#import <CFNetwork/CFNetwork.h>
+
+#define CFSafeRelease(pp_cf) if (pp_cf && *pp_cf) CFRelease(*pp_cf), *pp_cf = NULL;
+#if !defined (TNET_AUTODETECT_RUNLOOP_MODE)
+# define TNET_AUTODETECT_RUNLOOP_MODE "org.doubango.proxydetect.auto"
+#endif
+
+typedef struct appl_proxyinfo_xs {
+ CFStringRef host;
+ int port;
+ CFStringRef username;
+ CFStringRef password;
+ CFStringRef type;
+}
+appl_proxyinfo_xt;
+
+static tnet_proxy_type_t _appl_proxy_type_convert(CFStringRef cfProxyType);
+static void _appl_proxyinfo_release(appl_proxyinfo_xt * info);
+static tsk_bool_t _appl_proxyinfo_is_valid(const appl_proxyinfo_xt * info);
+static void _ProxyAutoConfigurationResultCallback(void *client, CFArrayRef proxyList, CFErrorRef error);
+static void _appl_find_best_proxy(CFURLRef cfTargetURL, CFArrayRef _cfProxies, appl_proxyinfo_xt *_proxyInfo);
+
+tnet_proxyinfo_t* tnet_proxydetect_get_info(const char* url, tnet_socket_type_t socket_type, tsk_bool_t long_operation)
+{
+ tnet_proxyinfo_t* info = tsk_null;
+ CFStringRef cfUrl = CFStringCreateWithCString(CFAllocatorGetDefault(), url, kCFStringEncodingUTF8);
+ CFURLRef cfTargetUrl = CFURLCreateWithString(CFAllocatorGetDefault(), cfUrl, NULL);
+ CFDictionaryRef cfProxySettings = NULL;
+ CFArrayRef cfProxies = NULL;
+ appl_proxyinfo_xt _info = { 0 };
+ if (!cfTargetUrl) {
+ TSK_DEBUG_ERROR("Failed to create CFURLRef from %s", url);
+ goto resolve_done;
+ }
+ cfProxySettings = CFNetworkCopySystemProxySettings();
+ if (!cfProxySettings) {
+ TSK_DEBUG_ERROR("CFNetworkCopySystemProxySettings returned nil");
+ goto resolve_done;
+ }
+
+ cfProxies = CFNetworkCopyProxiesForURL(cfTargetUrl, cfProxySettings);
+ if (!cfProxies) {
+ TSK_DEBUG_ERROR("CFNetworkCopyProxiesForURL returned 0-array");
+ goto resolve_done;
+ }
+ // find best proxy
+ _appl_find_best_proxy(cfTargetUrl, cfProxies, &_info);
+
+
+resolve_done:
+ if (cfUrl) {
+ CFRelease(cfUrl);
+ }
+ if (cfTargetUrl) {
+ CFRelease(cfTargetUrl);
+ }
+ if (cfProxySettings) {
+ CFRelease(cfProxySettings);
+ }
+ if (cfProxies) {
+ CFRelease(cfProxies);
+ }
+
+ if (_appl_proxyinfo_is_valid(&_info)) {
+ info = tnet_proxyinfo_create();
+ if (info) {
+ info->type = _appl_proxy_type_convert(_info.type);
+ info->socket_type = socket_type;
+ info->port = _info.port;
+ info->hostname = tsk_strdup(CFStringGetCStringPtr(_info.host, kCFStringEncodingUTF8));
+ info->username = tsk_strdup(CFStringGetCStringPtr(_info.username, kCFStringEncodingUTF8));
+ info->password = tsk_strdup(CFStringGetCStringPtr(_info.password, kCFStringEncodingUTF8));
+ }
+ }
+ _appl_proxyinfo_release(&_info);
+
+ return info;
+}
+
+static tsk_bool_t _appl_proxyinfo_is_valid(const appl_proxyinfo_xt * info)
+{
+ if (info) {
+ return info->port
+ && info->type && !CFEqual(info->type, kCFProxyTypeNone)
+ && info->host && CFStringGetLength(info->host) > 0 && CFStringCompare(info->host, CFSTR("127.0.0.1"), 0) != kCFCompareEqualTo;
+ }
+ return tsk_false;
+}
+
+static tnet_proxy_type_t _appl_proxy_type_convert(CFStringRef cfProxyType)
+{
+ if (CFEqual(cfProxyType, kCFProxyTypeHTTP) || CFEqual(cfProxyType, kCFProxyTypeHTTPS)) {
+ // kCFProxyTypeHTTPS: means the destination url is "https://" not the proxy connection type is HTTPS
+ return tnet_proxy_type_http;
+ }
+ else if(CFEqual(cfProxyType,kCFProxyTypeSOCKS)) {
+ return tnet_proxy_type_socks5;
+ }
+ else {
+ return tnet_proxy_type_none;
+ }
+}
+
+static void _appl_proxyinfo_release(appl_proxyinfo_xt * info)
+{
+ if (info) {
+ CFSafeRelease(&info->host);
+ CFSafeRelease(&info->username);
+ CFSafeRelease(&info->password);
+ CFSafeRelease(&info->type);
+ info->port = 0;
+ }
+}
+
+static void _ProxyAutoConfigurationResultCallback(void *client, CFArrayRef proxyList, CFErrorRef error)
+{
+ CFTypeRef* cfResult = (CFTypeRef*)client;
+ if (error != NULL) {
+ *cfResult = CFRetain(error);
+ } else {
+ *cfResult = CFRetain(proxyList);
+ }
+ CFRunLoopStop(CFRunLoopGetCurrent());
+}
+
+static void _appl_find_best_proxy(CFURLRef cfTargetURL, CFArrayRef _cfProxies, appl_proxyinfo_xt *_proxyInfo)
+{
+ CFDictionaryRef cfProxy;
+ CFIndex index = 0;
+ CFIndex count = CFArrayGetCount(_cfProxies);
+
+ while (index < count && (cfProxy = CFArrayGetValueAtIndex(_cfProxies, index++)) && !_appl_proxyinfo_is_valid(_proxyInfo)) {
+ _appl_proxyinfo_release(_proxyInfo);
+ CFStringRef cfProxyType = CFDictionaryGetValue(cfProxy, (const void*)kCFProxyTypeKey);
+ if (!cfProxyType) {
+ continue;
+ }
+
+ TSK_DEBUG_INFO("Found at %li proxy type = %s", (index - 1), CFStringGetCStringPtr(cfProxyType, kCFStringEncodingUTF8));
+ if (CFEqual(cfProxyType, kCFProxyTypeNone)) {
+ continue;
+ }
+ else if (CFEqual(cfProxyType, kCFProxyTypeHTTP) || CFEqual(cfProxyType, kCFProxyTypeHTTPS) || CFEqual(cfProxyType, kCFProxyTypeSOCKS)) {
+ // "kCFProxyTypeHTTPS" means the url is "https://" not the connection should be TLS
+ CFStringRef cfHostName = (CFStringRef)CFDictionaryGetValue(cfProxy, (const void*)kCFProxyHostNameKey);
+ if (cfHostName) {
+ CFNumberRef cfPortNumber = (CFNumberRef)CFDictionaryGetValue(cfProxy, (const void*)kCFProxyPortNumberKey);
+ if (cfPortNumber) {
+ int port = 0;
+ if (!CFNumberGetValue(cfPortNumber, kCFNumberSInt32Type, &port)) {
+ continue;
+ }
+ _proxyInfo->port = port;
+ _proxyInfo->host = CFStringCreateCopy(CFAllocatorGetDefault(), cfHostName);
+ _proxyInfo->type = CFStringCreateCopy(CFAllocatorGetDefault(), cfProxyType);
+ CFStringRef cfStringName = (CFStringRef)CFDictionaryGetValue(cfProxy, (const void*)kCFProxyUsernameKey);
+ if (cfStringName) {
+ _proxyInfo->username = CFStringCreateCopy(CFAllocatorGetDefault(), cfStringName);
+ }
+ CFStringRef cfPassword = (CFStringRef)CFDictionaryGetValue(cfProxy, (const void*)kCFProxyPasswordKey);
+ if (cfPassword) {
+ _proxyInfo->password = CFStringCreateCopy(CFAllocatorGetDefault(), cfPassword);
+ }
+ }
+ }
+ }
+ else if (CFEqual(cfProxyType, kCFProxyTypeAutoConfigurationURL)) {
+ CFURLRef cfPACUrl = (CFURLRef)CFDictionaryGetValue(cfProxy, (const void*)kCFProxyAutoConfigurationURLKey);
+ if (cfPACUrl) {
+ TSK_DEBUG_INFO("Found at %li PACUrl = %s", (index - 1), CFStringGetCStringPtr(CFURLGetString(cfPACUrl), kCFStringEncodingUTF8));
+ CFTypeRef cfResult = NULL;
+ CFStreamClientContext context = { 0, &cfResult, NULL, NULL, NULL };
+ CFRunLoopSourceRef cfrunLoop = CFNetworkExecuteProxyAutoConfigurationURL(cfPACUrl,
+ cfTargetURL,
+ _ProxyAutoConfigurationResultCallback,
+ &context);
+ if (!cfrunLoop) {
+ TSK_DEBUG_ERROR("CFNetworkExecuteProxyAutoConfigurationURL(%li, %s) failed", (index - 1), CFStringGetCStringPtr(CFURLGetString(cfPACUrl), kCFStringEncodingUTF8));
+ continue;
+ }
+ static const CFStringRef kPrivateRunloopMode = CFSTR(TNET_AUTODETECT_RUNLOOP_MODE);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), cfrunLoop, kPrivateRunloopMode);
+ CFRunLoopRunInMode(kPrivateRunloopMode, DBL_MAX, false);
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), cfrunLoop, kPrivateRunloopMode);
+ if (cfResult == NULL) {
+ TSK_DEBUG_INFO("Result from ProxyAutoConfigurationResultCallback is nil");
+ continue;
+ }
+ if (CFGetTypeID(cfResult) == CFErrorGetTypeID()) {
+ CFStringRef cfErrorDescription = CFErrorCopyDescription ((CFErrorRef)cfResult);
+ TSK_DEBUG_ERROR("Result from ProxyAutoConfigurationResultCallback is error: %s", CFStringGetCStringPtr(cfErrorDescription, kCFStringEncodingUTF8));
+ CFRelease(cfErrorDescription);
+ }
+ else if (CFGetTypeID(cfResult) == CFArrayGetTypeID()) {
+ TSK_DEBUG_INFO("Result from ProxyAutoConfigurationResultCallback is array");
+ _appl_find_best_proxy(cfTargetURL, (CFArrayRef)cfResult, _proxyInfo);
+ }
+ CFRelease(cfResult);
+ }
+ else {
+ TSK_DEBUG_INFO("PACUrl at %li is nil", (index - 1));
+ }
+ }
+ }
+}
+
+/******** Not supported ************/
+#else
+
+tnet_proxyinfo_t* tnet_proxydetect_get_info(const char* url, tnet_socket_type_t socket_type, tsk_bool_t long_operation)
+{
+ TSK_DEBUG_WARN("Proxy detection not supported on your OS");
+ return tsk_null;
+}
+
+#endif /* END-OF-CONDITIONAL-OS-IMPL */
+
+
+tsk_bool_t tnet_proxyinfo_is_valid(const tnet_proxyinfo_t* self)
+{
+ if (self) {
+ return self->port && self->type != tnet_proxy_type_none && !tsk_strnullORempty(self->hostname);
+ }
+ return tsk_false;
+}
+
diff --git a/tinyNET/src/tnet_proxydetect.h b/tinyNET/src/tnet_proxydetect.h
new file mode 100644
index 0000000..23c5439
--- /dev/null
+++ b/tinyNET/src/tnet_proxydetect.h
@@ -0,0 +1,51 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+#ifndef TNET_PROXYDETECT_H
+#define TNET_PROXYDETECT_H
+
+#include "tinynet_config.h"
+#include "tnet_types.h"
+#include "tnet_socket.h"
+
+TNET_BEGIN_DECLS
+
+typedef struct tnet_proxyinfo_s {
+ TSK_DECLARE_OBJECT;
+
+ tnet_proxy_type_t type;
+ char* autoconfig_url;
+ tsk_bool_t autodetect;
+ char* bypass_list;
+ char* hostname;
+ tnet_socket_type_t socket_type;
+ tnet_port_t port;
+ char* username;
+ char* password;
+}
+tnet_proxyinfo_t;
+
+TINYNET_API tnet_proxyinfo_t* tnet_proxyinfo_create();
+TINYNET_API tnet_proxyinfo_t* tnet_proxydetect_get_info(const char* url, tnet_socket_type_t socket_type, tsk_bool_t long_operation);
+#define tnet_proxydetect_get_info_fast(url, socket_type) tnet_proxydetect_get_info((url), (socket_type), tsk_false)
+TINYNET_API tsk_bool_t tnet_proxyinfo_is_valid(const tnet_proxyinfo_t* self);
+
+TNET_END_DECLS
+
+#endif /* TNET_PROXYDETECT_H */
diff --git a/tinyNET/src/tnet_socket.c b/tinyNET/src/tnet_socket.c
new file mode 100644
index 0000000..2d104d1
--- /dev/null
+++ b/tinyNET/src/tnet_socket.c
@@ -0,0 +1,339 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet.h
+ * @brief Protocol agnostic socket.
+ *
+ */
+
+#include "tnet_socket.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+/**@defgroup tnet_socket_group Protocol agnostic socket
+*
+*
+* <h2>10.1 Sockets</h2>
+* For performance reason, all sockets created using tinyNET are non-blocking by default.
+* The newly created socket will be automatically bound to associate it with an IP address and port number. @ref tnet_socket_create() function is used to create and bind a
+* non-blocking socket. You should use @ref tnet_socket_create_2() function to control whether the socket should be bound or not. The same function is used to force the stack to create a blocking socket.<br>
+* A socket object is defined like this:<br>
+*
+* @code
+typedef struct tnet_socket_s
+{
+TSK_DECLARE_OBJECT;
+
+tnet_socket_type_t type;
+tnet_fd_t fd;
+tnet_ip_t ip;
+uint16_t port;
+
+tnet_tls_socket_handle_t* tlshandle;
+}
+tnet_socket_t;
+* @endcode
+* To create a socket:
+* @code
+// (create udp ipv4 or ipv6 socket)
+tnet_socket_t* socket = tnet_socket_create(
+TNET_SOCKET_HOST_ANY, // local ip address/hostname to bind to
+TNET_SOCKET_PORT_ANY, // local port number to bind to
+tnet_socket_type_udp_ipv46 // the socket type (IPv4 or IPv6)
+);
+// TNET_SOCKET_HOST_ANY --> bind to "0.0.0.0" or "::"
+// TNET_SOCKET_PORT_ANY --> bind to any available port
+* @endcode
+
+* <b>TNET_SOCKET_TYPE_IS_*()</b> macros are used to determine:
+* - The socket type (stream, dgram),
+* - The socket protocol (udp, tcp, tls, sctp, ipsec),
+* - The IP version (ipv6, ipv4),
+* - …
+* <br>
+* A socket is a well-defined object and should be destroyed using @a TSK_DECLARE_SAFE_FREE() macro.
+* A socket will be automatically closed when destroyed.
+*
+*/
+
+static int tnet_socket_close(tnet_socket_t *sock);
+
+/**@ingroup tnet_socket_group
+* Creates a new socket.
+* To check that the returned socket is valid use @ref TNET_SOCKET_IS_VALID function.
+* @param host FQDN (e.g. www.doubango.org) or IPv4/IPv6 IP string.
+* @param port The local/remote port used to receive/send data. Set the port value to @ref TNET_SOCKET_PORT_ANY to bind to a random port.
+* @param type The type of the socket. See @ref tnet_socket_type_t.
+* @param nonblocking Indicates whether to create non-blocking socket.
+* @param bindsocket Indicates whether to bind the newly created socket or not.
+* @retval @ref tnet_socket_t object.
+* @sa @ref tnet_socket_create.
+*/
+tnet_socket_t* tnet_socket_create_2(const char* host, tnet_port_t port_, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket)
+{
+ tnet_socket_t *sock;
+ if ((sock = tsk_object_new(tnet_socket_def_t))) {
+ int status;
+ tsk_istr_t port;
+ struct addrinfo *result = tsk_null;
+ struct addrinfo *ptr = tsk_null;
+ struct addrinfo hints;
+ tnet_host_t local_hostname;
+
+ sock->port = port_;
+ tsk_itoa(sock->port, &port);
+ sock->type = type;
+
+ memset(local_hostname, 0, sizeof(local_hostname));
+
+ /* Get the local host name */
+ if (host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){
+ memcpy(local_hostname, host, tsk_strlen(host) > sizeof(local_hostname) - 1 ? sizeof(local_hostname) - 1 : tsk_strlen(host));
+ }
+ else{
+ if (TNET_SOCKET_TYPE_IS_IPV6(sock->type)){
+ memcpy(local_hostname, "::", 2);
+ }
+ else {
+ memcpy(local_hostname, "0.0.0.0", 7);
+ }
+ }
+
+ /* hints address info structure */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET);
+ hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM;
+ hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP;
+ hints.ai_flags = AI_PASSIVE
+#if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600
+ | AI_ADDRCONFIG
+#endif
+ ;
+
+ /* Performs getaddrinfo */
+ if ((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))) {
+ TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]",
+ hints.ai_family, local_hostname, port, tnet_gai_strerror(status));
+ goto bail;
+ }
+
+ /* Find our address. */
+ for (ptr = result; ptr; ptr = ptr->ai_next){
+ sock->fd = (tnet_fd_t)tnet_soccket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
+ if (ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){
+ continue;
+ }
+ /* To avoid "Address already in use" error
+ * Check issue 368 (https://code.google.com/p/doubango/issues/detail?id=368) to understand why it's not used for UDP/DTLS.
+ */
+ //
+ if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) {
+ if ((status = tnet_sockfd_reuseaddr(sock->fd, 1))) {
+ // do not break...continue
+ }
+ }
+
+ if (bindsocket){
+ /* Bind the socket */
+ if ((status = bind(sock->fd, ptr->ai_addr, (int)ptr->ai_addrlen))){
+ TNET_PRINT_LAST_ERROR("bind to [%s:%s]have failed", local_hostname, port);
+ tnet_socket_close(sock);
+ continue;
+ }
+
+ /* Get local IP string. */
+ if ((status = tnet_get_ip_n_port(sock->fd, tsk_true/*local*/, &sock->ip, &sock->port))) /* % */
+ //if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST)))
+ {
+ TNET_PRINT_LAST_ERROR("Failed to get local IP and port.");
+ tnet_socket_close(sock);
+ continue;
+ }
+ }
+
+ /* sets the real socket type (if ipv46) */
+ if (ptr->ai_family == AF_INET6) {
+ TNET_SOCKET_TYPE_SET_IPV6Only(sock->type);
+ }
+ else {
+ TNET_SOCKET_TYPE_SET_IPV4Only(sock->type);
+ }
+ break;
+ }
+
+ /* Check socket validity. */
+ if (!TNET_SOCKET_IS_VALID(sock)) {
+ TNET_PRINT_LAST_ERROR("Invalid socket.");
+ goto bail;
+ }
+
+#if TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR
+ /* disable SIGPIPE signal */
+ {
+ int yes = 1;
+ if (setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(int))){
+ TNET_PRINT_LAST_ERROR("setsockopt(SO_NOSIGPIPE) have failed.");
+ }
+ }
+#endif /* TNET_UNDER_IPHONE */
+
+ /* Sets the socket to nonblocking mode */
+ if(nonblocking){
+ if((status = tnet_sockfd_set_nonblocking(sock->fd))){
+ goto bail;
+ }
+ }
+
+ bail:
+ /* Free addrinfo */
+ tnet_freeaddrinfo(result);
+
+ /* Close socket if failed. */
+ if (status){
+ if (TNET_SOCKET_IS_VALID(sock)){
+ tnet_socket_close(sock);
+ }
+ return tsk_null;
+ }
+}
+
+ return sock;
+}
+
+/**@ingroup tnet_socket_group
+* Creates a non-blocking socket and bind it.
+* To check that the returned socket is valid use @ref TNET_SOCKET_IS_VALID function.
+* @param host FQDN (e.g. www.doubango.org) or IPv4/IPv6 IP string.
+* @param port The local/remote port used to receive/send data. Set the port value to @ref TNET_SOCKET_PORT_ANY to bind to a random port.
+* @param type The type of the socket. See @ref tnet_socket_type_t.
+* @retval @ref tnet_socket_t object.
+*/
+tnet_socket_t* tnet_socket_create(const char* host, tnet_port_t port, tnet_socket_type_t type)
+{
+ return tnet_socket_create_2(host, port, type, tsk_true, tsk_true);
+}
+
+/**@ingroup tnet_socket_group
+* Returns the number of bytes sent (or negative value on error)
+*/
+int tnet_socket_send_stream(tnet_socket_t* self, const void* data, tsk_size_t size)
+{
+ if (!self || self->fd == TNET_INVALID_FD || !data || !size || !TNET_SOCKET_TYPE_IS_STREAM(self->type)) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (self->tlshandle && (TNET_SOCKET_TYPE_IS_TLS(self->type) || TNET_SOCKET_TYPE_IS_WSS(self->type))) {
+ return tnet_tls_socket_send(self->tlshandle, data, size) == 0 ? (int)size : -1; // returns zero on success
+ }
+
+ return (int)tnet_sockfd_send(self->fd, data, size, 0);
+}
+
+/**@ingroup tnet_socket_group
+ * @retval Zero if succeed and nonzero error code otherwise.
+ */
+int tnet_socket_handle_brokenpipe(tnet_socket_t* self)
+{
+ int ret;
+ tnet_fd_t fd_old, fd_new;
+ if (!self || !TNET_SOCKET_TYPE_IS_DGRAM(self->type)) { // Must be UDP
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ fd_old = self->fd;
+ fd_new = TNET_INVALID_FD;
+
+ // close old fd
+ ret = tnet_sockfd_close(&self->fd);
+ // try to create an fd binding to the same address
+ if ((ret = tnet_sockfd_init(self->ip, self->port, self->type, &fd_new)) != 0) {
+ TNET_PRINT_LAST_ERROR("Find to bind to %s:%d", self->ip, self->port);
+ // TODO: Create completly new socket?
+ return ret;
+ }
+#if TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR
+ /* disable SIGPIPE signal */
+ {
+ int yes = 1;
+ if (setsockopt(fd_new, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(int))){
+ TNET_PRINT_LAST_ERROR("setsockopt(%d, SO_NOSIGPIPE) have failed", fd_new);
+ }
+ }
+#endif /* TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR */
+ TSK_DEBUG_INFO("Broken pipe result for {%s:%d}: %d -> %d", self->ip, self->port, fd_old, fd_new);
+ self->fd = fd_new;
+ return 0;
+}
+
+/**@ingroup tnet_socket_group
+ * Closes a socket.
+ * @param sock The socket to close.
+ * @retval Zero if succeed and nonzero error code otherwise.
+ **/
+static int tnet_socket_close(tnet_socket_t *sock)
+{
+ return tnet_sockfd_close(&(sock->fd));
+}
+
+//=================================================================================================
+// SOCKET object definition
+//
+static tsk_object_t* tnet_socket_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_socket_t *sock = self;
+ if (sock){
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_socket_dtor(tsk_object_t * self)
+{
+ tnet_socket_t *sock = self;
+
+ if (sock){
+ /* Close the socket */
+ if (TNET_SOCKET_IS_VALID(sock)){
+ tnet_socket_close(sock);
+ }
+ /* Clean up TLS handle */
+ TSK_OBJECT_SAFE_FREE(sock->tlshandle);
+
+ /* Clean up DTLS handle */
+ TSK_OBJECT_SAFE_FREE(sock->dtlshandle);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_socket_def_s =
+{
+ sizeof(tnet_socket_t),
+ tnet_socket_ctor,
+ tnet_socket_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_socket_def_t = &tnet_socket_def_s;
+
+
diff --git a/tinyNET/src/tnet_socket.h b/tinyNET/src/tnet_socket.h
new file mode 100644
index 0000000..3c7dc34
--- /dev/null
+++ b/tinyNET/src/tnet_socket.h
@@ -0,0 +1,201 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet.h
+ * @brief Protocol agnostic socket.
+ *
+ */
+#ifndef TNET_SOCKET_H
+#define TNET_SOCKET_H
+
+#include "tinynet_config.h"
+#include "tnet_types.h"
+#include "tls/tnet_tls.h"
+#include "tls/tnet_dtls.h"
+
+#include "tsk_list.h"
+
+/** List of all supported socket types.
+* @def tnet_socket_type_e
+**/
+TNET_BEGIN_DECLS
+
+
+typedef enum tnet_socket_type_e
+{
+ tnet_socket_type_invalid = 0x0000, /**< Invalid socket.*/
+
+#define TNET_SOCKET_TYPE_IPV4 (0x0001 << 0)
+#define TNET_SOCKET_TYPE_UDP (0x0001 << 1)
+#define TNET_SOCKET_TYPE_DTLS (0x0001 << 2)
+#define TNET_SOCKET_TYPE_TCP (0x0001 << 3)
+#define TNET_SOCKET_TYPE_TLS (0x0001 << 4)
+#define TNET_SOCKET_TYPE_SCTP (0x0001 << 5)
+#define TNET_SOCKET_TYPE_WS (0x0001 << 6)
+#define TNET_SOCKET_TYPE_WSS (0x0001 << 7)
+ tnet_socket_type_udp_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_UDP), /**< UDP/IPv4 socket.*/
+ tnet_socket_type_dtls_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_DTLS), /**< DTLS/IPv4 socket.*/
+ tnet_socket_type_tcp_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_TCP), /**< TCP/IPv4 socket.*/
+ tnet_socket_type_tls_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_TLS), /**< TLS/IPv4 socket.*/
+ tnet_socket_type_sctp_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_SCTP), /**< SCTP/IPv4 socket.*/
+ tnet_socket_type_ws_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_WS), /**< WebSocket/IPv4 socket.*/
+ tnet_socket_type_wss_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_WSS), /**< WebSocket Secure/IPv4 socket.*/
+
+#define TNET_SOCKET_TYPE_IPSEC (0x0001 << 8)
+ tnet_socket_type_udp_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_udp_ipv4), /**< UDP/IPSec/IPv4 socket.*/
+ tnet_socket_type_dtls_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_dtls_ipv4), /**< DTLS/IPSec/IPv4 socket.*/
+ tnet_socket_type_tcp_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tcp_ipv4), /**< TCP/IPSec/IPv4 socket.*/
+ tnet_socket_type_tls_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tls_ipv4), /**< TLS/IPSec /IPv4socket.*/
+ tnet_socket_type_sctp_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_sctp_ipv4), /**< SCTP/IPSec/IPv4 socket.*/
+ tnet_socket_type_ws_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_ws_ipv4), /**< WS/IPSec/IPv4 socket.*/
+ tnet_socket_type_wss_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_wss_ipv4), /**< WSS/IPSec/IPv4 socket.*/
+
+#define TNET_SOCKET_TYPE_IPV6 (0x0001 << 12)
+ tnet_socket_type_udp_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_udp_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< UDP/IPv6 socket.*/
+ tnet_socket_type_dtls_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_dtls_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< DTLS/IPv6 socket.*/
+ tnet_socket_type_tcp_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_tcp_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< TCP/IPv6 socket.*/
+ tnet_socket_type_tls_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_tls_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< TLS/IPv6 socket.*/
+ tnet_socket_type_sctp_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_sctp_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< SCTP/IPv6 socket.*/
+ tnet_socket_type_ws_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_ws_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< WS/IPv6 socket.*/
+ tnet_socket_type_wss_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_wss_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< WSS/IPv6 socket.*/
+ tnet_socket_type_udp_ipsec_ipv6 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_udp_ipv6), /**< UDP/IPSec/IPv6 socket.*/
+ tnet_socket_type_tcp_ipsec_ipv6 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tcp_ipv6), /**< TCP/IPSec/IPv6 socket.*/
+ tnet_socket_type_tls_ipsec_ipv6 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tls_ipv6), /**< TLS/IPSec/IPv6 socket.*/
+ tnet_socket_type_sctp_ipsec_ipv6 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_sctp_ipv6),/**< SCTP/IPSec/IPv6 socket.*/
+ tnet_socket_type_ws_ipsec_ipv6 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_ws_ipv6), /**< WS/IPSec/IPv6 socket.*/
+ tnet_socket_type_wss_ipsec_ipv6 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_wss_ipv6),/**< WSS/IPSec/IPv6 socket.*/
+
+#define TNET_SOCKET_TYPE_IPV46 (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_IPV6)
+ tnet_socket_type_udp_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_udp_ipv4 | tnet_socket_type_udp_ipv6)), /**< UDP/IPv4/6 socket.*/
+ tnet_socket_type_dtls_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_dtls_ipv4 | tnet_socket_type_dtls_ipv6)), /**< DTLS/IPv4/6 socket.*/
+ tnet_socket_type_tcp_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_tcp_ipv4 | tnet_socket_type_tcp_ipv6)), /**< TCP/IPv4/6 socket.*/
+ tnet_socket_type_tls_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_tls_ipv4 | tnet_socket_type_tls_ipv6)), /**< TLS/IPv4/6 socket.*/
+ tnet_socket_type_sctp_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_sctp_ipv4 | tnet_socket_type_sctp_ipv6)), /**< SCTP/IPv4/6 socket.*/
+ tnet_socket_type_ws_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_ws_ipv4 | tnet_socket_type_ws_ipv6)), /**< WS/IPv4/6 socket.*/
+ tnet_socket_type_wss_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_wss_ipv4 | tnet_socket_type_wss_ipv6)), /**< WSS/IPv4/6 socket.*/
+ tnet_socket_type_udp_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_udp_ipv46), /**< UDP/IPSec/IPv4/6 socket.*/
+ tnet_socket_type_dtls_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_dtls_ipv46), /**< DTLS/IPSec/IPv4/6 socket.*/
+ tnet_socket_type_tcp_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tcp_ipv46), /**< TCP/IPSec/IPv4/6 socket.*/
+ tnet_socket_type_tls_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tls_ipv46), /**< TLS/IPSec/IPv4/6 socket.*/
+ tnet_socket_type_sctp_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_sctp_ipv46),/**< SCTP/IPSec/IPv4/6 socket.*/
+ tnet_socket_type_ws_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_ws_ipv46),/**< WS/IPSec/IPv4/6 socket.*/
+ tnet_socket_type_wss_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_wss_ipv46),/**< WSS/IPSec/IPv4/6 socket.*/
+}
+tnet_socket_type_t;
+
+
+/**@def TNET_SOCKET_IS_VALID
+* Checks the socket validity.
+*/
+#define TNET_SOCKET_IS_VALID(socket) ((socket) && TNET_SOCKET_TYPE_IS_VALID((socket)->type) && (socket)->fd >0)
+#define TNET_SOCKET_TYPE_IS_VALID(type) ((type) !=tnet_socket_type_invalid)
+
+#define TNET_SOCKET_TYPE_IS_STREAM(type) ( ((type & TNET_SOCKET_TYPE_UDP) != TNET_SOCKET_TYPE_UDP) && ((type & TNET_SOCKET_TYPE_DTLS) != TNET_SOCKET_TYPE_DTLS) )
+#define TNET_SOCKET_TYPE_IS_DGRAM(type) ( !TNET_SOCKET_TYPE_IS_STREAM((type)) )
+
+#define TNET_SOCKET_TYPE_IS_IPV4(type) ( ((type & TNET_SOCKET_TYPE_IPV4) == TNET_SOCKET_TYPE_IPV4) )
+#define TNET_SOCKET_TYPE_IS_IPV6(type) ( ((type & TNET_SOCKET_TYPE_IPV6) == TNET_SOCKET_TYPE_IPV6) )
+#define TNET_SOCKET_TYPE_IS_IPV46(type) ( TNET_SOCKET_TYPE_IS_IPV4(type) && TNET_SOCKET_TYPE_IS_IPV6(type) )
+
+#define TNET_SOCKET_TYPE_IS_IPSEC(type) ( ((type & TNET_SOCKET_TYPE_IPSEC) == TNET_SOCKET_TYPE_IPSEC) )
+
+#define TNET_SOCKET_TYPE_IS_UDP(type) ( ((type & TNET_SOCKET_TYPE_UDP) == TNET_SOCKET_TYPE_UDP) )
+#define TNET_SOCKET_TYPE_IS_DTLS(type) ( ((type & TNET_SOCKET_TYPE_DTLS) == TNET_SOCKET_TYPE_DTLS) )
+#define TNET_SOCKET_TYPE_IS_TCP(type) ( ((type & TNET_SOCKET_TYPE_TCP) == TNET_SOCKET_TYPE_TCP) )
+#define TNET_SOCKET_TYPE_IS_TLS(type) ( ((type & TNET_SOCKET_TYPE_TLS) == TNET_SOCKET_TYPE_TLS) )
+#define TNET_SOCKET_TYPE_IS_SCTP(type) ( ((type & TNET_SOCKET_TYPE_SCTP) == TNET_SOCKET_TYPE_SCTP) )
+#define TNET_SOCKET_TYPE_IS_WS(type) ( ((type & TNET_SOCKET_TYPE_WS) == TNET_SOCKET_TYPE_WS) )
+#define TNET_SOCKET_TYPE_IS_WSS(type) ( ((type & TNET_SOCKET_TYPE_WSS) == TNET_SOCKET_TYPE_WSS) )
+
+#define TNET_SOCKET_TYPE_IS_SECURE(type) ( TNET_SOCKET_TYPE_IS_IPSEC(type) || TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_DTLS(type) || TNET_SOCKET_TYPE_IS_WSS(type) )
+
+#define TNET_SOCKET_TYPE_UNSET(type, OP) (type = TNET_SOCKET_TYPE_IS_##OP(type) ? type ^= TNET_SOCKET_TYPE_##OP : type)
+#define TNET_SOCKET_TYPE_SET(type, OP) (type |= TNET_SOCKET_TYPE_##OP)
+
+#define TNET_SOCKET_TYPE_SET_IPV4(type) (type |= TNET_SOCKET_TYPE_IPV4)
+#define TNET_SOCKET_TYPE_SET_IPV4Only(type) (type = TNET_SOCKET_TYPE_IS_IPV6(type) ? (type ^TNET_SOCKET_TYPE_IPV6)|TNET_SOCKET_TYPE_IPV4 : type)
+#define TNET_SOCKET_TYPE_SET_IPV6(type) (type |= TNET_SOCKET_TYPE_IPV6)
+#define TNET_SOCKET_TYPE_SET_IPV6Only(type) (type = TNET_SOCKET_TYPE_IS_IPV4(type) ? (type ^TNET_SOCKET_TYPE_IPV4)|TNET_SOCKET_TYPE_IPV6 : type)
+
+#define TNET_SOCKET_TYPE_SET_IPSEC(type) (type |=TNET_SOCKET_TYPE_IPSEC)
+
+#define TNET_SOCKET_TYPE_SET_UDP(type)\
+ (TNET_SOCKET_TYPE_UNSET(type,TCP), TNET_SOCKET_TYPE_UNSET(type,TLS), TNET_SOCKET_TYPE_UNSET(type,SCTP), TNET_SOCKET_TYPE_UNSET(type,WS), TNET_SOCKET_TYPE_UNSET(type,WSS), TNET_SOCKET_TYPE_UNSET(type,DTLS), type |=TNET_SOCKET_TYPE_UDP)
+#define TNET_SOCKET_TYPE_SET_DTLS(type)\
+ (TNET_SOCKET_TYPE_UNSET(type,TCP), TNET_SOCKET_TYPE_UNSET(type,TLS), TNET_SOCKET_TYPE_UNSET(type,SCTP), TNET_SOCKET_TYPE_UNSET(type,WS), TNET_SOCKET_TYPE_UNSET(type,WSS), TNET_SOCKET_TYPE_UNSET(type,UDP), type |=TNET_SOCKET_TYPE_DTLS)
+#define TNET_SOCKET_TYPE_SET_TCP(type)\
+ (TNET_SOCKET_TYPE_UNSET(type,UDP), TNET_SOCKET_TYPE_UNSET(type,TLS), TNET_SOCKET_TYPE_UNSET(type,SCTP), TNET_SOCKET_TYPE_UNSET(type,WS), TNET_SOCKET_TYPE_UNSET(type,WSS), TNET_SOCKET_TYPE_UNSET(type,DTLS), type |=TNET_SOCKET_TYPE_TCP)
+#define TNET_SOCKET_TYPE_SET_TLS(type)\
+ (TNET_SOCKET_TYPE_UNSET(type,TCP), TNET_SOCKET_TYPE_UNSET(type,UDP), TNET_SOCKET_TYPE_UNSET(type,SCTP), TNET_SOCKET_TYPE_UNSET(type,WS), TNET_SOCKET_TYPE_UNSET(type,WSS), TNET_SOCKET_TYPE_UNSET(type,DTLS), type |=TNET_SOCKET_TYPE_TLS)
+#define TNET_SOCKET_TYPE_SET_SCTP(type)\
+ (TNET_SOCKET_TYPE_UNSET(type,TCP), TNET_SOCKET_TYPE_UNSET(type,TLS), TNET_SOCKET_TYPE_UNSET(type,UDP), TNET_SOCKET_TYPE_UNSET(type,WS), TNET_SOCKET_TYPE_UNSET(type,WSS), TNET_SOCKET_TYPE_UNSET(type,DTLS), type |=TNET_SOCKET_TYPE_SCTP)
+#define TNET_SOCKET_TYPE_SET_WS(type)\
+ (TNET_SOCKET_TYPE_UNSET(type,TCP), TNET_SOCKET_TYPE_UNSET(type,TLS), TNET_SOCKET_TYPE_UNSET(type,UDP), TNET_SOCKET_TYPE_UNSET(type,SCTP), TNET_SOCKET_TYPE_UNSET(type,WSS), TNET_SOCKET_TYPE_UNSET(type,DTLS), type |=TNET_SOCKET_TYPE_WS)
+#define TNET_SOCKET_TYPE_SET_WSS(type)\
+ (TNET_SOCKET_TYPE_UNSET(type,TCP), TNET_SOCKET_TYPE_UNSET(type,TLS), TNET_SOCKET_TYPE_UNSET(type,UDP), TNET_SOCKET_TYPE_UNSET(type,WS), TNET_SOCKET_TYPE_UNSET(type,SCTP), TNET_SOCKET_TYPE_UNSET(type,DTLS), type |=TNET_SOCKET_TYPE_WSS)
+
+/**
+* @def TNET_SOCKET_HOST_ANY
+* Any IPv4/IPv6 host.
+*/
+/**
+* @def TNET_SOCKET_PORT_ANY
+* Any port.
+*/
+#define TNET_SOCKET_HOST_ANY tsk_null
+#define TNET_SOCKET_PORT_ANY 0
+
+/**
+* Socket.
+*/
+typedef struct tnet_socket_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_socket_type_t type;
+ tnet_fd_t fd;
+ tnet_ip_t ip;
+ uint16_t port;
+
+ tnet_tls_socket_handle_t* tlshandle;
+ tnet_dtls_socket_handle_t* dtlshandle;
+}
+tnet_socket_t;
+
+typedef tnet_socket_t tnet_socket_udp_t; /**< UDP socket. */
+typedef tnet_socket_t tnet_socket_tcp_t; /**< TCP socket. */
+typedef tnet_socket_t tnet_socket_tls_t; /**< TLS socket. */
+typedef tnet_socket_t tnet_socket_ws_t; /**< WS socket. */
+typedef tnet_socket_t tnet_socket_wss_t; /**< WSS socket. */
+typedef tnet_socket_t tnet_socket_ipsec_t; /**< IPSec socket. */
+typedef tsk_list_t tnet_sockets_L_t; /**< List of @ref tnet_socket_t elements. */
+
+TINYNET_API tnet_socket_t* tnet_socket_create_2(const char*host, tnet_port_t port, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket);
+TINYNET_API tnet_socket_t* tnet_socket_create(const char* host, tnet_port_t port, tnet_socket_type_t type);
+TINYNET_API int tnet_socket_send_stream(tnet_socket_t* self, const void* data, tsk_size_t size);
+TINYNET_API int tnet_socket_handle_brokenpipe(tnet_socket_t* self);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_socket_def_t;
+
+
+TNET_END_DECLS
+
+#endif /* TNET_SOCKET_H */
+
diff --git a/tinyNET/src/tnet_transport.c b/tinyNET/src/tnet_transport.c
new file mode 100644
index 0000000..7d26d08
--- /dev/null
+++ b/tinyNET/src/tnet_transport.c
@@ -0,0 +1,1116 @@
+/*
+ * Copyright (C) 2010-2015 Mamadou DIOP.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+
+/**@file tnet_transport.c
+ * @brief Network transport layer.
+ *
+ * <h2>10.2 Tansport</h2>
+ * A transport layer always has a master socket which determine what kind of network traffic we expect (stream or dgram).
+ * Stream transport can manage TCP, TLS and SCTP sockets. Datagram socket can only manage UDP sockets. <br>
+ * A transport can hold both IPv4 and IPv6 sockets.
+ */
+#include "tnet_transport.h"
+#include "tnet_proxy_plugin.h"
+#include "tnet_proxydetect.h"
+#include "tls/tnet_tls.h"
+#include "tls/tnet_dtls.h"
+
+#include "stun/tnet_stun_types.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+#include "tsk_thread.h"
+#include "tsk_buffer.h"
+
+#include <string.h> /* memcpy, ...(<#void * #>, <#const void * #>, <#tsk_size_t #>) */
+
+#ifndef TNET_CIPHER_LIST
+# define TNET_CIPHER_LIST "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
+#endif
+
+extern int tnet_transport_prepare(tnet_transport_t *transport);
+extern int tnet_transport_unprepare(tnet_transport_t *transport);
+extern void* TSK_STDCALL tnet_transport_mainthread(void *param);
+extern int tnet_transport_stop(tnet_transport_t *transport);
+
+static void* TSK_STDCALL run(void* self);
+static int _tnet_transport_dtls_cb(const void* usrdata, tnet_dtls_socket_event_type_t e, const tnet_dtls_socket_handle_t* handle, const void* data, tsk_size_t size);
+
+static int _tnet_transport_ssl_init(tnet_transport_t* transport)
+{
+ if (!transport){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+#if HAVE_OPENSSL
+ {
+ tnet_socket_type_t type = tnet_transport_get_type(transport);
+ tsk_bool_t is_tls = (TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type));
+ tsk_bool_t is_dtls = transport->dtls.enabled/* TNET_SOCKET_TYPE_IS_DTLS(type)*/; // DTLS-RTP, not raw DTLS
+ if (is_dtls && !tnet_dtls_is_supported()){
+ TSK_DEBUG_ERROR("Requesting to create DTLS transport but source code not built with support for this feature");
+ return -1;
+ }
+ if (is_tls && !tnet_tls_is_supported()){
+ TSK_DEBUG_ERROR("Requesting to create TLS transport but source code not built with support for this feature");
+ return -1;
+ }
+ if ((transport->tls.enabled = is_tls)){
+ if (!transport->tls.ctx_client && !(transport->tls.ctx_client = SSL_CTX_new(SSLv23_client_method()))){
+ TSK_DEBUG_ERROR("Failed to create SSL client context");
+ return -2;
+ }
+ if (!transport->tls.ctx_server && !(transport->tls.ctx_server = SSL_CTX_new(SSLv23_server_method()))){
+ TSK_DEBUG_ERROR("Failed to create SSL server context");
+ return -3;
+ }
+ SSL_CTX_set_mode(transport->tls.ctx_client, SSL_MODE_AUTO_RETRY);
+ SSL_CTX_set_mode(transport->tls.ctx_server, SSL_MODE_AUTO_RETRY);
+ SSL_CTX_set_verify(transport->tls.ctx_server, SSL_VERIFY_NONE, tsk_null); // to be updated by tnet_transport_tls_set_certs()
+ SSL_CTX_set_verify(transport->tls.ctx_client, SSL_VERIFY_NONE, tsk_null); // to be updated by tnet_transport_tls_set_certs()
+ if (SSL_CTX_set_cipher_list(transport->tls.ctx_client, TNET_CIPHER_LIST) <= 0 || SSL_CTX_set_cipher_list(transport->tls.ctx_server, TNET_CIPHER_LIST) <= 0){
+ TSK_DEBUG_ERROR("SSL_CTX_set_cipher_list failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ return -4;
+ }
+ }
+#if HAVE_OPENSSL_DTLS
+ if ((transport->dtls.enabled = is_dtls)){
+ if (!transport->dtls.ctx && !(transport->dtls.ctx = SSL_CTX_new(DTLSv1_method()))){
+ TSK_DEBUG_ERROR("Failed to create DTLSv1 context");
+ TSK_OBJECT_SAFE_FREE(transport);
+ return -5;
+ }
+ SSL_CTX_set_read_ahead(transport->dtls.ctx, 1);
+ // SSL_CTX_set_options(transport->dtls.ctx, SSL_OP_ALL);
+ // SSL_CTX_set_mode(transport->dtls.ctx, SSL_MODE_AUTO_RETRY);
+ SSL_CTX_set_verify(transport->dtls.ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, tsk_null); // to be updated by tnet_transport_tls_set_certs()
+ if (SSL_CTX_set_cipher_list(transport->dtls.ctx, TNET_CIPHER_LIST) <= 0){
+ TSK_DEBUG_ERROR("SSL_CTX_set_cipher_list failed [%s]", ERR_error_string(ERR_get_error(), tsk_null));
+ return -6;
+ }
+ //!\ This is required even if the local transport is TCP/TLS because the relayed (TURN) transport could be UDP
+ // Up to the DTLS socket to set the default MTU value
+ SSL_CTX_set_options(transport->dtls.ctx, SSL_OP_NO_QUERY_MTU);
+ SSL_CTX_ctrl(transport->dtls.ctx, SSL_CTRL_SET_MTU, TNET_DTLS_MTU - 28, NULL);
+
+ transport->dtls.activated = tsk_true;
+ }
+#endif /* HAVE_OPENSSL_DTLS */
+ }
+#endif /* HAVE_OPENSSL */
+
+ return 0;
+}
+
+static int _tnet_transport_ssl_deinit(tnet_transport_t* transport)
+{
+ if (!transport){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+#if HAVE_OPENSSL
+ if (transport->tls.ctx_client){
+ SSL_CTX_free(transport->tls.ctx_client);
+ transport->tls.ctx_client = tsk_null;
+ }
+ if (transport->tls.ctx_server){
+ SSL_CTX_free(transport->tls.ctx_server);
+ transport->tls.ctx_server = tsk_null;
+ }
+ if (transport->dtls.ctx){
+ SSL_CTX_free(transport->dtls.ctx);
+ transport->dtls.ctx = tsk_null;
+ }
+#endif /* HAVE_OPENSSL */
+ return 0;
+}
+
+tnet_transport_t* tnet_transport_create(const char* host, tnet_port_t port, tnet_socket_type_t type, const char* description)
+{
+ tnet_transport_t* transport;
+
+ if ((transport = tsk_object_new(tnet_transport_def_t))){
+ transport->description = tsk_strdup(description);
+ transport->local_host = tsk_strdup(host);
+ transport->req_local_port = port;
+ transport->type = type;
+ transport->context = tnet_transport_context_create();
+
+ if ((transport->master = tnet_socket_create(transport->local_host, transport->req_local_port, transport->type))){
+ transport->local_ip = tsk_strdup(transport->master->ip);
+ transport->bind_local_port = transport->master->port;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create master socket");
+ TSK_OBJECT_SAFE_FREE(transport);
+ }
+
+ if (_tnet_transport_ssl_init(transport) != 0){
+ TSK_DEBUG_ERROR("Failed to initialize TLS and/or DTLS caps");
+ TSK_OBJECT_SAFE_FREE(transport);
+ }
+ // set priority
+ tsk_runnable_set_priority(TSK_RUNNABLE(transport), TSK_THREAD_PRIORITY_TIME_CRITICAL);
+ }
+
+ return transport;
+}
+
+tnet_transport_t* tnet_transport_create_2(tnet_socket_t *master, const char* description)
+{
+ tnet_transport_t* transport;
+ if (!master){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ if ((transport = tsk_object_new(tnet_transport_def_t))){
+ transport->description = tsk_strdup(description);
+ transport->local_host = tsk_strdup(master->ip);
+ transport->req_local_port = master->port;
+ transport->type = master->type;
+
+ transport->master = tsk_object_ref(master);
+ transport->local_ip = tsk_strdup(transport->master->ip);
+ transport->bind_local_port = transport->master->port;
+
+ transport->context = tnet_transport_context_create();
+
+ if (_tnet_transport_ssl_init(transport) != 0){
+ TSK_DEBUG_ERROR("Failed to initialize TLS and/or DTLS caps");
+ TSK_OBJECT_SAFE_FREE(transport);
+ }
+
+ // set priority
+ tsk_runnable_set_priority(TSK_RUNNABLE(transport), TSK_THREAD_PRIORITY_TIME_CRITICAL);
+ }
+
+ return transport;
+}
+
+tnet_transport_event_t* tnet_transport_event_create(tnet_transport_event_type_t type, const void* callback_data, tnet_fd_t fd)
+{
+ return tsk_object_new(tnet_transport_event_def_t, type, callback_data, fd);
+}
+
+int tnet_transport_tls_set_certs(tnet_transport_handle_t *handle, const char* ca, const char* pbk, const char* pvk, tsk_bool_t verify)
+{
+ tnet_transport_t *transport = handle;
+ static const char* ssl_password = tsk_null;
+
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_strupdate(&transport->tls.ca, ca);
+ tsk_strupdate(&transport->tls.pvk, pvk);
+ tsk_strupdate(&transport->tls.pbk, pbk);
+ transport->tls.verify = verify;
+
+#if HAVE_OPENSSL
+ {
+ int32_t i, ret;
+ SSL_CTX* contexts[3] = { tsk_null };
+
+ /* init DTLS/TLS contexts */
+ if ((ret = _tnet_transport_ssl_init(transport))){
+ return ret;
+ }
+
+ if (transport->tls.enabled){
+ contexts[0] = transport->tls.ctx_client;
+ contexts[1] = transport->tls.ctx_server;
+ }
+ if (transport->dtls.enabled){
+ contexts[2] = transport->dtls.ctx;
+ /* Reset fingerprints */
+ memset(transport->dtls.fingerprints, 0, sizeof(transport->dtls.fingerprints));
+ }
+
+ for (i = 0; i < sizeof(contexts) / sizeof(contexts[0]); ++i){
+ if (!contexts[i]){
+ continue;
+ }
+ SSL_CTX_set_verify(contexts[i], transport->tls.verify ? (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT) : SSL_VERIFY_NONE, tsk_null);
+ if (!tsk_strnullORempty(transport->tls.pbk) || !tsk_strnullORempty(transport->tls.pvk) || !tsk_strnullORempty(transport->tls.ca)){
+ /* Sets Public key (cert) */
+ if (!tsk_strnullORempty(transport->tls.pbk) && (ret = SSL_CTX_use_certificate_file(contexts[i], transport->tls.pbk, SSL_FILETYPE_PEM)) != 1) {
+ TSK_DEBUG_ERROR("SSL_CTX_use_certificate_file failed [%d,%s]", ret, ERR_error_string(ERR_get_error(), tsk_null));
+ return -3;
+ }
+ /*Sets the password of the private key*/
+ if (!tsk_strnullORempty(ssl_password)){
+ SSL_CTX_set_default_passwd_cb_userdata(contexts[i], (void*)ssl_password);
+ }
+
+ /* Sets Private key (cert) */
+ if (!tsk_strnullORempty(transport->tls.pvk) && (ret = SSL_CTX_use_PrivateKey_file(contexts[i], transport->tls.pvk, SSL_FILETYPE_PEM)) != 1) {
+ TSK_DEBUG_ERROR("SSL_CTX_use_PrivateKey_file failed [%d,%s]", ret, ERR_error_string(ERR_get_error(), tsk_null));
+ return -4;
+ }
+ /* Checks private key */
+ if (!tsk_strnullORempty(transport->tls.pvk) && SSL_CTX_check_private_key(contexts[i]) == 0) {
+ TSK_DEBUG_ERROR("SSL_CTX_check_private_key failed [%d,%s]", ret, ERR_error_string(ERR_get_error(), tsk_null));
+ return -5;
+ }
+ /* Sets trusted CAs and CA file */
+ if (!tsk_strnullORempty(transport->tls.ca) && (ret = SSL_CTX_load_verify_locations(contexts[i], transport->tls.ca, /*tlsdir_cas*/tsk_null)) != 1) {
+ TSK_DEBUG_ERROR("SSL_CTX_load_verify_locations failed [%d, %s]", ret, ERR_error_string(ERR_get_error(), tsk_null));
+ return -5;
+ }
+ }
+ }
+ }
+#endif /* HAVE_OPENSSL */
+
+ return 0;
+}
+
+int tnet_transport_start(tnet_transport_handle_t* handle)
+{
+ int ret = -1;
+ if (handle){
+ tnet_transport_t *transport = handle;
+
+ /* prepare transport */
+ if ((ret = tnet_transport_prepare(transport))){
+ TSK_DEBUG_ERROR("Failed to prepare transport.");
+ goto bail;
+ }
+
+ /* start transport */
+ TSK_RUNNABLE(transport)->run = run;
+ if ((ret = tsk_runnable_start(TSK_RUNNABLE(transport), tnet_transport_event_def_t))){
+ TSK_DEBUG_ERROR("Failed to start transport.");
+ goto bail;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ }
+
+bail:
+ return ret;
+}
+
+int tnet_transport_issecure(const tnet_transport_handle_t *handle)
+{
+ if (handle)
+ {
+ const tnet_transport_t *transport = handle;
+ if (transport->master){
+ return TNET_SOCKET_TYPE_IS_SECURE(transport->master->type);
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ }
+ return 0;
+}
+
+const char* tnet_transport_get_description(const tnet_transport_handle_t *handle)
+{
+ if (handle){
+ const tnet_transport_t *transport = handle;
+ return transport->description;
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ return tsk_null;
+ }
+}
+
+int tnet_transport_get_ip_n_port(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port)
+{
+ if (handle){
+ return tnet_get_ip_n_port(fd, tsk_true/*local*/, ip, port);
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ }
+ return -1;
+}
+
+int tnet_transport_get_ip_n_port_2(const tnet_transport_handle_t *handle, tnet_ip_t *ip, tnet_port_t *port)
+{
+ const tnet_transport_t *transport = handle;
+ if (transport){
+ // do not check the master, let the application die if "null"
+ if (ip){
+ memcpy(*ip, transport->master->ip, sizeof(transport->master->ip));
+ }
+ if (port){
+ *port = transport->master->port;
+ }
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ return -1;
+ }
+}
+
+int tnet_transport_set_natt_ctx(tnet_transport_handle_t *handle, struct tnet_nat_ctx_s* natt_ctx)
+{
+ if (!handle) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ TSK_OBJECT_SAFE_FREE(((tnet_transport_t *)handle)->natt_ctx);
+ ((tnet_transport_t *)handle)->natt_ctx = tsk_object_ref(natt_ctx);
+ return 0;
+}
+
+int tnet_transport_get_public_ip_n_port(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port)
+{
+ tsk_bool_t stun_ok = tsk_false;
+ struct tnet_nat_ctx_s* natt_ctx;
+ const tnet_transport_t *transport = handle;
+ if (!transport){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (TNET_SOCKET_TYPE_IS_DGRAM(transport->type) && (natt_ctx = tsk_object_ref(transport->natt_ctx))) {
+ tnet_stun_binding_id_t bind_id = kStunBindingInvalidId;
+ // if the socket is already monitored by the transport we should pause because both the transport and
+ // NAT binder will try to read from it
+
+ // Pause the soket
+ tnet_transport_pause_socket(transport, fd, tsk_true);
+ // Performs STUN binding
+ bind_id = tnet_nat_stun_bind(transport->natt_ctx, fd);
+ // Resume the socket
+ tnet_transport_pause_socket(transport, fd, tsk_false);
+
+ if (bind_id != kStunBindingInvalidId) {
+ char* public_ip = tsk_null;
+ if (tnet_nat_stun_get_reflexive_address(transport->natt_ctx, bind_id, &public_ip, port) == 0){
+ if (ip && public_ip){
+ tsk_size_t ip_len = tsk_strlen(public_ip);
+ memcpy(ip, public_ip, ip_len > sizeof(*ip) ? sizeof(*ip) : ip_len);
+ }
+ stun_ok = tsk_true;
+ }
+ TSK_FREE(public_ip);
+ tnet_nat_stun_unbind(transport->natt_ctx, bind_id);
+ }
+ tsk_object_unref(natt_ctx);
+ }
+
+ if (!stun_ok){
+ if (fd == TNET_INVALID_FD && transport->local_ip){
+ memcpy(*ip, transport->local_ip, TSK_MIN(sizeof(tnet_ip_t), tsk_strlen(transport->local_ip)));
+ *port = transport->bind_local_port;
+ return 0;
+ }
+ else{
+ return tnet_transport_get_ip_n_port(handle, fd, ip, port);
+ }
+ }
+
+ return 0;
+}
+
+const char* tnet_transport_dtls_get_local_fingerprint(const tnet_transport_handle_t *handle, tnet_dtls_hash_type_t hash)
+{
+ const tnet_transport_t *transport = handle;
+
+ if (!transport){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ if (!transport->dtls.enabled){
+ TSK_DEBUG_ERROR("DTLS not enabled on this transport");
+ return tsk_null;
+ }
+ if (hash > sizeof(transport->dtls.fingerprints) / sizeof(transport->dtls.fingerprints[0])){
+ TSK_DEBUG_ERROR("%d not valid for fingerprint hash", hash);
+ return tsk_null;
+ }
+ if (tsk_strnullORempty(transport->tls.pbk)){
+ TSK_DEBUG_ERROR("No certificate for which to get fingerprint");
+ return tsk_null;
+ }
+
+ if (tnet_dtls_get_fingerprint(transport->tls.pbk, &((tnet_transport_t *)transport)->dtls.fingerprints[hash], hash) == 0){
+ return (const char*)transport->dtls.fingerprints[hash];
+ }
+ return tsk_null;
+}
+
+/*
+ rfc5764: 4.1. The use_srtp Extension
+ */
+int tnet_transport_dtls_use_srtp(tnet_transport_handle_t *handle, const char* srtp_profiles, struct tnet_socket_s** sockets, tsk_size_t sockets_count)
+{
+ tnet_transport_t *transport = handle;
+
+ if (!transport || !srtp_profiles){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!transport->dtls.enabled){
+ TSK_DEBUG_ERROR("DTLS not enabled on this transport");
+ return -2;
+ }
+#if HAVE_OPENSSL_DTLS_SRTP
+ {
+ tsk_size_t i;
+ transport->dtls.use_srtp = tsk_true;
+ SSL_CTX_set_tlsext_use_srtp(transport->dtls.ctx, srtp_profiles);
+ if (sockets){
+ for (i = 0; i < sockets_count; ++i){
+ if (sockets[i] && sockets[i]->dtlshandle){
+ tnet_dtls_socket_use_srtp(sockets[i]->dtlshandle);
+ }
+ }
+ }
+ return 0;
+ }
+#else
+ TSK_DEBUG_ERROR("Your OpenSSL version do not support DTLS-SRTP");
+ return -2;
+#endif
+}
+
+int tnet_transport_dtls_set_remote_fingerprint(tnet_transport_handle_t *handle, const tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash, struct tnet_socket_s** sockets, tsk_size_t sockets_count)
+{
+ const tnet_transport_t *transport = handle;
+
+ if (!transport || !fingerprint){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!transport->dtls.enabled){
+ TSK_DEBUG_ERROR("DTLS not enabled on this transport");
+ return -2;
+ }
+#if HAVE_OPENSSL_DTLS
+ if (sockets){
+ tsk_size_t i;
+ for (i = 0; i < sockets_count; ++i){
+ if (sockets[i] && sockets[i]->dtlshandle){
+ tnet_dtls_socket_set_remote_fingerprint(sockets[i]->dtlshandle, fingerprint, hash);
+ }
+ }
+ }
+ return 0;
+#else
+ TSK_DEBUG_ERROR("Your OpenSSL version do not support DTLS");
+ return -2;
+#endif
+}
+
+tsk_bool_t tnet_transport_dtls_is_enabled(const tnet_transport_handle_t *handle)
+{
+ const tnet_transport_t *transport = handle;
+ if (!transport){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return transport->dtls.enabled;
+}
+
+/*
+ Enable or disable DTLS on the transport and all coresponding sockets
+ *@param handle The transport for which to enable or disable DTLS
+ *@param enabled Whether to enable or disable DTLS
+ *@param sockets List of all sockets for which to enable or disable DLS could be null. You should include the master socket in this list.
+ *@param sockets_count The number of sockets
+ *@return 0 if succeed, otherwise non-zero error code
+ */
+int tnet_transport_dtls_set_enabled(tnet_transport_handle_t *handle, tsk_bool_t enabled, struct tnet_socket_s** sockets, tsk_size_t sockets_count)
+{
+ tnet_transport_t *transport = handle;
+ tnet_socket_type_t type;
+ int ret;
+
+ if (!transport){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ type = tnet_transport_get_type(transport);
+
+ if (enabled & !tnet_dtls_is_supported()) {
+ TSK_DEBUG_ERROR("Trying to enable DTLS but code source not built with this feature");
+ return -1;
+ }
+
+ if ((transport->dtls.enabled = enabled)) {
+ if ((ret = _tnet_transport_ssl_init(transport))) {
+ return ret;
+ }
+ }
+ else {
+ ret = _tnet_transport_ssl_deinit(transport);
+ }
+
+ if (sockets && sockets_count) {
+ tsk_size_t i;
+ for (i = 0; i < sockets_count; ++i) {
+ if (!sockets[i]) {
+ continue;
+ }
+ if (enabled) {
+ if (!sockets[i]->dtlshandle) {
+ if (!(sockets[i]->dtlshandle = tnet_dtls_socket_create(sockets[i], transport->dtls.ctx))) {
+ return -4;
+ }
+ }
+ if (transport->dtls.use_srtp) {
+ tnet_dtls_socket_use_srtp(sockets[i]->dtlshandle);
+ }
+ tnet_dtls_socket_set_callback(sockets[i]->dtlshandle, transport, _tnet_transport_dtls_cb);
+ }
+ else {
+ TSK_OBJECT_SAFE_FREE(sockets[i]->dtlshandle);
+ }
+ }
+ }
+
+ return ret;
+}
+
+int tnet_transport_dtls_set_setup(tnet_transport_handle_t* handle, tnet_dtls_setup_t setup, struct tnet_socket_s** sockets, tsk_size_t sockets_count)
+{
+ tnet_transport_t *transport = handle;
+
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!transport->dtls.enabled) {
+ TSK_DEBUG_ERROR("DTLS not enabled on this transport");
+ return -2;
+ }
+ if (sockets && sockets_count) {
+ tsk_size_t i;
+ for (i = 0; i < sockets_count; ++i) {
+ if (!sockets[i] || !sockets[i]->dtlshandle) {
+ continue;
+ }
+ tnet_dtls_socket_set_setup(sockets[i]->dtlshandle, setup);
+ }
+ }
+ return 0;
+}
+
+int tnet_transport_dtls_set_store_handshakingdata(tnet_transport_handle_t* handle, tsk_bool_t handshake_storedata, struct tnet_socket_s** sockets, tsk_size_t sockets_count)
+{
+ tnet_transport_t *transport = handle;
+
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!transport->dtls.enabled) {
+ TSK_DEBUG_ERROR("DTLS not enabled on this transport");
+ return -2;
+ }
+ if (sockets && sockets_count) {
+ tsk_size_t i;
+ for (i = 0; i < sockets_count; ++i) {
+ if (!sockets[i] || !sockets[i]->dtlshandle) {
+ continue;
+ }
+ tnet_dtls_socket_set_store_handshakingdata(sockets[i]->dtlshandle, handshake_storedata);
+ }
+ }
+ return 0;
+}
+
+int tnet_transport_dtls_do_handshake(tnet_transport_handle_t *handle, struct tnet_socket_s** sockets, tsk_size_t sockets_count, const struct sockaddr_storage** remote_addrs, tsk_size_t remote_addrs_count)
+{
+ tnet_transport_t *transport = handle;
+ tsk_size_t i;
+
+ if (!transport || !sockets) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!transport->dtls.enabled) {
+ TSK_DEBUG_ERROR("DTLS not enabled on this transport");
+ return -2;
+ }
+
+ if (sockets) {
+ int ret;
+ for (i = 0; i < sockets_count; ++i) {
+ if (sockets[i] && sockets[i]->dtlshandle) {
+ if ((ret = tnet_dtls_socket_do_handshake(sockets[i]->dtlshandle,
+ (remote_addrs && i < remote_addrs_count) ? remote_addrs[i] : tsk_null)) != 0){
+ return ret;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int tnet_transport_dtls_get_handshakingdata(tnet_transport_handle_t* handle, const struct tnet_socket_s** sockets, tsk_size_t sockets_count, const void* data[], tsk_size_t size[])
+{
+ tnet_transport_t *transport = handle;
+ tsk_size_t i;
+
+ if (!transport || !sockets) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!transport->dtls.enabled) {
+ TSK_DEBUG_ERROR("DTLS not enabled on this transport");
+ return -2;
+ }
+
+ if (sockets) {
+ int ret;
+ for (i = 0; i < sockets_count; ++i) {
+ if (sockets[i] && sockets[i]->dtlshandle) {
+ if ((ret = tnet_dtls_socket_get_handshakingdata(sockets[i]->dtlshandle, &data[i], &size[i])) != 0){
+ return ret;
+ }
+ }
+ else {
+ data[i] = tsk_null;
+ size[i] = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+tnet_socket_type_t tnet_transport_get_type(const tnet_transport_handle_t *handle)
+{
+ if (!handle){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tnet_socket_type_invalid;
+ }
+ return ((const tnet_transport_t *)handle)->type;
+}
+
+tnet_fd_t tnet_transport_get_master_fd(const tnet_transport_handle_t *handle)
+{
+ if (!handle){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return TNET_INVALID_FD;
+ }
+ return ((const tnet_transport_t *)handle)->master ? ((const tnet_transport_t *)handle)->master->fd : TNET_INVALID_FD;
+}
+
+int tnet_transport_get_bytes_count(const tnet_transport_handle_t *handle, uint64_t* bytes_in, uint64_t* bytes_out)
+{
+ if (!handle){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (bytes_in) *bytes_in = ((const tnet_transport_t *)handle)->bytes_in;
+ if (bytes_out) *bytes_out = ((const tnet_transport_t *)handle)->bytes_out;
+ return 0;
+}
+
+/**
+ * Connects a socket.
+ * @param handle The transport to use to connect() the socket. The new socket will be managed by this transport.
+ * @param host The remote @a host to connect() to.
+ * @param port The remote @a port to connect() to.
+ * @param type The type of the socket to use to connect() to the remote @a host.
+ * @retval The newly connected socket. For non-blocking sockets you should use @ref tnet_sockfd_waitUntilWritable to check
+ * the socket for writability.
+ * @sa tnet_sockfd_waitUntilWritable.
+ */
+tnet_fd_t tnet_transport_connectto(const tnet_transport_handle_t *handle, const char* host, tnet_port_t port, tnet_socket_type_t type)
+{
+ return tnet_transport_connectto_3(handle, tsk_null/*socket*/, host, port, type);
+}
+
+tnet_fd_t tnet_transport_connectto_3(const tnet_transport_handle_t *handle, struct tnet_socket_s* socket, const char* host, tnet_port_t port, tnet_socket_type_t type)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ struct sockaddr_storage to;
+ int status = -1;
+ tnet_fd_t fd = socket ? socket->fd : TNET_INVALID_FD;
+ tnet_tls_socket_handle_t* tls_handle = tsk_null;
+ tsk_bool_t owe_socket = socket ? tsk_false : tsk_true;
+ tsk_bool_t use_proxy = TNET_SOCKET_TYPE_IS_STREAM(type);
+ const char* to_host = host;
+ tnet_port_t to_port = port;
+ tnet_socket_type_t to_type = type;
+ tnet_proxyinfo_t* proxy_info = tsk_null;
+
+ if (!transport || !transport->master) {
+ TSK_DEBUG_ERROR("Invalid transport handle");
+ goto bail;
+ }
+
+ if ((TNET_SOCKET_TYPE_IS_STREAM(transport->master->type) && !TNET_SOCKET_TYPE_IS_STREAM(type)) ||
+ (TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type) && !TNET_SOCKET_TYPE_IS_DGRAM(type))) {
+ TSK_DEBUG_ERROR("Master/destination types mismatch [%u/%u]", transport->master->type, type);
+ goto bail;
+ }
+
+ if (use_proxy) {
+ // auto-detect the proxy
+ if (transport->proxy.auto_detect) {
+ char* url = tsk_null;
+ // The proxy detection implementations are designed for a browser and expect a "http://" or "https://" schemes (will work with socks).
+ tsk_sprintf(&url, "%s://%s:%d", TNET_SOCKET_TYPE_IS_TLS(to_type) ? "https" : "http", to_host, to_port);
+ proxy_info = tnet_proxydetect_get_info_fast(url, to_type);
+ TSK_FREE(url);
+ }
+ // fall-back to the hard proxy if auto-detection failed
+ if (!tnet_proxyinfo_is_valid(proxy_info) && tnet_proxyinfo_is_valid(transport->proxy.info)) {
+ proxy_info = tsk_object_ref(transport->proxy.info);
+ }
+ }
+
+ use_proxy &= tnet_proxyinfo_is_valid(proxy_info);
+ if (use_proxy) {
+ if (tnet_proxy_node_is_nettransport_supported(proxy_info->type, type)) {
+ to_host = proxy_info->hostname;
+ to_port = proxy_info->port;
+ // SOCKS still doesn't define RFC for SSL security (https://tools.ietf.org/html/draft-ietf-aft-socks-ssl-00) but Kerberos6 authentication is supported
+ if (proxy_info->type == tnet_proxy_type_http || proxy_info->type == tnet_proxy_type_socks4 || proxy_info->type == tnet_proxy_type_socks4a || proxy_info->type == tnet_proxy_type_socks5) {
+ // Send CONNET to the proxy using unsecure connection then begin SSL handshaking if needed
+ TNET_SOCKET_TYPE_UNSET(to_type, TLS); // Make the type unsecure (will keep other flags-e.g. IP version-)
+ TNET_SOCKET_TYPE_SET(to_type, TCP); // Use plain TCP
+ }
+ }
+ else {
+ // Not an error.
+ TSK_DEBUG_INFO("No proxy plugin to handle network transport type = %d", type);
+ use_proxy = tsk_false;
+ }
+ }
+
+ TSK_DEBUG_INFO("tnet_transport_connectto_3(host=%s, port=%d, type=%d, fd=%d, use_proxy=%d, to_host=%s, to_port=%d, to_type=%d, proxy_type=%d)" , host, port, type, fd, use_proxy, to_host, to_port, to_type, proxy_info ? proxy_info->type : 0);
+
+ /* Init destination sockaddr fields */
+ if ((status = tnet_sockaddr_init(to_host, to_port, to_type, &to))) {
+ TSK_DEBUG_ERROR("Invalid HOST/PORT [%s/%u]", host, port);
+ goto bail;
+ }
+ if (TNET_SOCKET_TYPE_IS_IPV46(type)) {
+ /* Update the type (unambiguously) */
+ if (to.ss_family == AF_INET6) {
+ TNET_SOCKET_TYPE_SET_IPV6Only(type);
+ }
+ else {
+ TNET_SOCKET_TYPE_SET_IPV4Only(type);
+ }
+ }
+
+ /*
+ * STREAM ==> create new socket and connect it to the remote host.
+ * DGRAM ==> connect the master to the remote host.
+ */
+ if (fd == TNET_INVALID_FD) {
+ // Create client socket descriptor.
+ if ((status = tnet_sockfd_init(transport->local_host, TNET_SOCKET_PORT_ANY, to_type, &fd))) {
+ TSK_DEBUG_ERROR("Failed to create new sockfd.");
+ goto bail;
+ }
+ }
+
+ if ((status = tnet_sockfd_connectto(fd, (const struct sockaddr_storage *)&to))) {
+ if (fd != transport->master->fd) {
+ tnet_sockfd_close(&fd);
+ }
+ goto bail;
+ }
+ else {
+ static const tsk_bool_t __isClient = tsk_true;
+ if (TNET_SOCKET_TYPE_IS_TLS(to_type) || TNET_SOCKET_TYPE_IS_WSS(to_type)) {
+#if HAVE_OPENSSL
+ tls_handle = tnet_tls_socket_create(fd, transport->tls.ctx_client);
+ if (socket) {
+ TSK_OBJECT_SAFE_FREE(socket->tlshandle);
+ socket->tlshandle = tsk_object_ref(tls_handle);
+ }
+ if ((status = tnet_tls_socket_connect(tls_handle))) {
+ tnet_sockfd_close(&fd);
+ goto bail;
+ }
+#endif
+ }
+ /* Add the socket */
+ // socket must be added after connect() otherwise many Linux systems will return POLLHUP as the fd is not active yet
+ if ((status = tnet_transport_add_socket_2(handle, fd, to_type, owe_socket, __isClient, tls_handle, host, port, proxy_info))) {
+ TNET_PRINT_LAST_ERROR("Failed to add new socket");
+ tnet_sockfd_close(&fd);
+ goto bail;
+ }
+ }
+
+bail:
+ TSK_OBJECT_SAFE_FREE(tls_handle);
+ TSK_OBJECT_SAFE_FREE(proxy_info);
+ return status == 0 ? fd : TNET_INVALID_FD;
+}
+
+int tnet_transport_set_callback(const tnet_transport_handle_t *handle, tnet_transport_cb_f callback, const void* callback_data)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return -1;
+ }
+
+ transport->callback = callback;
+ transport->callback_data = callback_data;
+ return 0;
+}
+
+int tnet_transport_set_proxy_auto_detect(tnet_transport_handle_t *handle, tsk_bool_t auto_detect)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return -1;
+ }
+ transport->proxy.auto_detect = auto_detect;
+ return 0;
+}
+
+int tnet_transport_set_proxy_info(tnet_transport_handle_t *handle, enum tnet_proxy_type_e type, const char* host, tnet_port_t port, const char* login, const char* password)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ tnet_proxyinfo_t* proxy_info;
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return -1;
+ }
+ if ((proxy_info = tnet_proxyinfo_create())) {
+ proxy_info->type = type;
+ proxy_info->hostname = tsk_strdup(host);
+ proxy_info->port = port;
+ proxy_info->username = tsk_strdup(login);
+ proxy_info->password = tsk_strdup(password);
+
+ TSK_OBJECT_SAFE_FREE(transport->proxy.info);
+ transport->proxy.info = proxy_info;
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+
+
+int tnet_transport_shutdown(tnet_transport_handle_t* handle)
+{
+ if (handle) {
+ int ret;
+ if ((ret = tnet_transport_stop(handle)) == 0){
+ ret = tnet_transport_unprepare(handle);
+ }
+ return ret;
+ }
+ else {
+ TSK_DEBUG_ERROR("NULL transport object.");
+ return -1;
+ }
+}
+
+
+static int _tnet_transport_dtls_cb(const void* usrdata, tnet_dtls_socket_event_type_t dtls_e, const tnet_dtls_socket_handle_t* handle, const void* data, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)usrdata;
+ if (transport) {
+ tnet_transport_event_type_t t_e;
+ const struct sockaddr_storage* remote_addr;
+ tnet_fd_t fd;
+ tnet_transport_event_t* e;
+
+ switch (dtls_e) {
+ case tnet_dtls_socket_event_type_handshake_started: t_e = event_dtls_handshake_started; break;
+ case tnet_dtls_socket_event_type_handshake_succeed: t_e = event_dtls_handshake_succeed; break;
+ case tnet_dtls_socket_event_type_handshake_failed: t_e = event_dtls_handshake_failed; break;
+ case tnet_dtls_socket_event_type_fingerprint_mismatch: t_e = event_dtls_fingerprint_mismatch; break;
+ case tnet_dtls_socket_event_type_dtls_srtp_profile_selected: t_e = event_dtls_srtp_profile_selected; break;
+ case tnet_dtls_socket_event_type_dtls_srtp_data: t_e = event_dtls_srtp_data; break;
+ case tnet_dtls_socket_event_type_error: t_e = event_dtls_error; break;
+ default: TSK_DEBUG_ERROR("DTLS event = %d ignored", dtls_e); return -1;
+ }
+ remote_addr = tnet_dtls_socket_get_remote_addr(handle);
+ fd = tnet_dtls_socket_get_fd(handle);
+ if ((e = tnet_transport_event_create(t_e, transport->callback_data, fd))) {
+ if (data && size && (e->data = tsk_malloc(size))) {
+ memcpy(e->data, data, size);
+ e->size = size;
+ }
+ if (remote_addr) {
+ e->remote_addr = *remote_addr;
+ }
+ if (TSK_RUNNABLE(transport)->initialized && TSK_RUNNABLE(transport)->running && TSK_RUNNABLE(transport)->started) {
+ TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
+ }
+ else {
+ TSK_DEBUG_INFO("Delivering network event synchronously.");
+ // network transport not started (happens when TURN is using the sockets instead of the RTP manager)
+ if (transport->callback) {
+ transport->callback(e);
+ }
+ TSK_OBJECT_SAFE_FREE(e);
+ }
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+/*
+ * Runnable interface implementation.
+ */
+static void* TSK_STDCALL run(void* self)
+{
+ int ret = 0;
+ tsk_list_item_t *curr;
+ tnet_transport_t *transport = self;
+
+ TSK_DEBUG_INFO("Transport::run(%s) - enter", transport->description);
+
+ /* create main thread */
+ if ((ret = tsk_thread_create(transport->mainThreadId, tnet_transport_mainthread, transport))){ /* More important than "tsk_runnable_start" ==> start it first. */
+ TSK_FREE(transport->context); /* Otherwise (tsk_thread_create is ok) will be freed when mainthread exit. */
+ TSK_DEBUG_FATAL("Failed to create main thread [%d]", ret);
+ return tsk_null;
+ }
+ /* set thread priority
+ iOS and OSX: no incoming pkts (STUN, rtp, dtls...) when thread priority is changed -> to be checked
+ */
+#if !TNET_UNDER_APPLE
+ ret = tsk_thread_set_priority(transport->mainThreadId[0], TSK_THREAD_PRIORITY_TIME_CRITICAL);
+#endif
+
+ TSK_RUNNABLE_RUN_BEGIN(transport);
+
+ if ((curr = TSK_RUNNABLE_POP_FIRST_SAFE(TSK_RUNNABLE(transport)))){
+ const tnet_transport_event_t *e = (const tnet_transport_event_t*)curr->data;
+
+ if (transport->callback) {
+ transport->callback(e);
+ }
+ tsk_object_unref(curr);
+ }
+
+ TSK_RUNNABLE_RUN_END(transport);
+
+ TSK_DEBUG_INFO("Transport::run(%s) - exit", transport->description);
+
+ return tsk_null;
+}
+
+
+
+
+//=================================================================================================
+// Transport object definition
+//
+static tsk_object_t* tnet_transport_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_transport_t *transport = self;
+ if (transport){
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_transport_dtor(tsk_object_t * self)
+{
+ tnet_transport_t *transport = self;
+ if (transport){
+ tnet_transport_set_callback(transport, tsk_null, tsk_null);
+ tnet_transport_shutdown(transport);
+ TSK_OBJECT_SAFE_FREE(transport->master);
+ TSK_OBJECT_SAFE_FREE(transport->context);
+ TSK_OBJECT_SAFE_FREE(transport->natt_ctx);
+ TSK_FREE(transport->local_ip);
+ TSK_FREE(transport->local_host);
+
+ // proxy
+ TSK_OBJECT_SAFE_FREE(transport->proxy.info);
+
+ // (tls and dtls) = ssl
+ TSK_FREE(transport->tls.ca);
+ TSK_FREE(transport->tls.pbk);
+ TSK_FREE(transport->tls.pvk);
+ _tnet_transport_ssl_deinit(transport); // openssl contexts
+
+ TSK_DEBUG_INFO("*** Transport (%s) destroyed ***", transport->description);
+ TSK_FREE(transport->description);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_transport_def_s =
+{
+ sizeof(tnet_transport_t),
+ tnet_transport_ctor,
+ tnet_transport_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_transport_def_t = &tnet_transport_def_s;
+
+
+
+//=================================================================================================
+// Transport event object definition
+//
+static tsk_object_t* tnet_transport_event_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_transport_event_t *e = self;
+ if (e){
+ e->type = va_arg(*app, tnet_transport_event_type_t);
+ e->callback_data = va_arg(*app, const void*);
+ e->local_fd = va_arg(*app, tnet_fd_t);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_transport_event_dtor(tsk_object_t * self)
+{
+ tnet_transport_event_t *e = self;
+ if (e){
+ TSK_FREE(e->data);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_transport_event_def_s =
+{
+ sizeof(tnet_transport_event_t),
+ tnet_transport_event_ctor,
+ tnet_transport_event_dtor,
+ 0,
+};
+const tsk_object_def_t *tnet_transport_event_def_t = &tnet_transport_event_def_s;
+
diff --git a/tinyNET/src/tnet_transport.h b/tinyNET/src/tnet_transport.h
new file mode 100644
index 0000000..c4da35b
--- /dev/null
+++ b/tinyNET/src/tnet_transport.h
@@ -0,0 +1,193 @@
+/*
+* Copyright (C) 2010-2012 Mamadou Diop.
+* Copyright (C) 2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_transport.h
+ * @brief Network transport layer.
+ *
+ */
+#ifndef TNET_SERVER_H
+#define TNET_SERVER_H
+
+#include "tinynet_config.h"
+
+#include "tnet_socket.h"
+#include "tnet_utils.h"
+#include "tnet_nat.h"
+
+#include "tsk_runnable.h"
+
+TNET_BEGIN_DECLS
+
+#define DGRAM_MAX_SIZE 8192
+#define STREAM_MAX_SIZE 8192
+
+#define TNET_TRANSPORT_CB_F(callback) ((tnet_transport_cb_f)callback)
+
+typedef enum tnet_transport_event_type_e
+{
+ event_data,
+ event_closed,
+ event_error,
+ event_removed,
+ event_connected,
+ event_accepted,
+ event_brokenpipe, // iOS: UDP sockets closed, to be restored now that the app is on foreground
+
+ event_dtls_handshake_started,
+ event_dtls_handshake_succeed,
+ event_dtls_handshake_failed,
+ event_dtls_fingerprint_mismatch,
+ event_dtls_srtp_data,
+ event_dtls_srtp_profile_selected,
+ event_dtls_error
+}
+tnet_transport_event_type_t;
+
+typedef struct tnet_transport_event_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_transport_event_type_t type;
+
+ void* data;
+ tsk_size_t size;
+
+ const void* callback_data;
+ tnet_fd_t local_fd;
+ struct sockaddr_storage remote_addr;
+}
+tnet_transport_event_t;
+
+typedef int (*tnet_transport_cb_f)(const tnet_transport_event_t* e);
+struct tnet_proxyinfo_s;
+
+TINYNET_API int tnet_transport_tls_set_certs(tnet_transport_handle_t *self, const char* ca, const char* pbk, const char* pvk, tsk_bool_t verify);
+TINYNET_API int tnet_transport_start(tnet_transport_handle_t* transport);
+TINYNET_API int tnet_transport_issecure(const tnet_transport_handle_t *handle);
+TINYNET_API const char* tnet_transport_get_description(const tnet_transport_handle_t *handle);
+TINYNET_API int tnet_transport_get_ip_n_port(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port);
+TINYNET_API int tnet_transport_get_ip_n_port_2(const tnet_transport_handle_t *handle, tnet_ip_t *ip, tnet_port_t *port);
+TINYNET_API int tnet_transport_set_natt_ctx(tnet_transport_handle_t *handle, struct tnet_nat_ctx_s* natt_ctx);
+TINYNET_API int tnet_transport_get_public_ip_n_port(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port);
+
+TINYNET_API int tnet_transport_isconnected(const tnet_transport_handle_t *handle, tnet_fd_t fd);
+TINYNET_API int tnet_transport_have_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd);
+TINYNET_API const tnet_tls_socket_handle_t* tnet_transport_get_tlshandle(const tnet_transport_handle_t *handle, tnet_fd_t fd);
+TINYNET_API int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t* tlsHandle);
+TINYNET_API int tnet_transport_add_socket_2(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t* tlsHandle, const char* dst_host, tnet_port_t dst_port, struct tnet_proxyinfo_s* proxy_info);
+TINYNET_API int tnet_transport_pause_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tsk_bool_t pause);
+TINYNET_API int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_t* fd);
+TINYNET_API tnet_fd_t tnet_transport_connectto(const tnet_transport_handle_t *handle, const char* host, tnet_port_t port, tnet_socket_type_t type);
+#define tnet_transport_connectto_2(handle, host, port) tnet_transport_connectto(handle, host, port, tnet_transport_get_type(handle))
+TINYNET_API tnet_fd_t tnet_transport_connectto_3(const tnet_transport_handle_t *handle, struct tnet_socket_s* socket, const char* host, tnet_port_t port, tnet_socket_type_t type);
+TINYNET_API tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t from, const void* buf, tsk_size_t size);
+TINYNET_API tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void* buf, tsk_size_t size);
+
+TINYNET_API int tnet_transport_set_callback(const tnet_transport_handle_t *handle, tnet_transport_cb_f callback, const void* callback_data);
+
+TINYNET_API int tnet_transport_set_proxy_auto_detect(tnet_transport_handle_t *handle, tsk_bool_t auto_detect);
+TINYNET_API int tnet_transport_set_proxy_info(tnet_transport_handle_t *handle, enum tnet_proxy_type_e type, const char* host, tnet_port_t port, const char* login, const char* password);
+
+TINYNET_API const char* tnet_transport_dtls_get_local_fingerprint(const tnet_transport_handle_t *handle, tnet_dtls_hash_type_t hash);
+#define tnet_transport_dtls_set_certs(self, ca, pbk, pvk, verify) tnet_transport_tls_set_certs((self), (ca), (pbk), (pvk), (verify))
+#define tnet_transport_dtls_srtp_set_certs(self, ca, pbk, pvk, verify) tnet_transport_dtls_set_certs((self), (ca), (pbk), (pvk), (verify))
+TINYNET_API int tnet_transport_dtls_use_srtp(tnet_transport_handle_t *handle, const char* srtp_profiles, struct tnet_socket_s** sockets, tsk_size_t sockets_count);
+TINYNET_API int tnet_transport_dtls_set_remote_fingerprint(tnet_transport_handle_t *handle, const tnet_fingerprint_t* fingerprint, tnet_dtls_hash_type_t hash, struct tnet_socket_s** sockets, tsk_size_t sockets_count);
+TINYNET_API tsk_bool_t tnet_transport_dtls_is_enabled(const tnet_transport_handle_t *handle);
+TINYNET_API int tnet_transport_dtls_set_enabled(tnet_transport_handle_t *handle, tsk_bool_t enabled, struct tnet_socket_s** sockets, tsk_size_t sockets_count);
+TINYNET_API int tnet_transport_dtls_set_setup(tnet_transport_handle_t* handle, tnet_dtls_setup_t setup, struct tnet_socket_s** sockets, tsk_size_t sockets_count);
+TINYNET_API int tnet_transport_dtls_set_store_handshakingdata(tnet_transport_handle_t* handle, tsk_bool_t handshake_storedata, struct tnet_socket_s** sockets, tsk_size_t sockets_count);
+TINYNET_API int tnet_transport_dtls_do_handshake(tnet_transport_handle_t *handle, struct tnet_socket_s** sockets, tsk_size_t sockets_count, const struct sockaddr_storage** remote_addrs, tsk_size_t remote_addrs_count);
+TINYNET_API int tnet_transport_dtls_get_handshakingdata(tnet_transport_handle_t* handle, const struct tnet_socket_s** sockets, tsk_size_t sockets_count, const void* data[], tsk_size_t size[]);
+
+TINYNET_API tnet_socket_type_t tnet_transport_get_type(const tnet_transport_handle_t *handle);
+TINYNET_API tnet_fd_t tnet_transport_get_master_fd(const tnet_transport_handle_t *handle);
+TINYNET_API int tnet_transport_get_bytes_count(const tnet_transport_handle_t *handle, uint64_t* bytes_in, uint64_t* bytes_out);
+TINYNET_API int tnet_transport_shutdown(tnet_transport_handle_t* handle);
+
+typedef struct tnet_transport_s
+{
+ TSK_DECLARE_RUNNABLE;
+
+ tnet_socket_type_t type;
+ char* local_ip;
+ char* local_host;
+ tnet_port_t req_local_port; // user requested local port
+ tnet_port_t bind_local_port; // local port on which we are listening (same as master socket)
+ struct tnet_nat_ctx_s* natt_ctx;
+ tnet_socket_t *master;
+
+ tsk_object_t *context;
+ tsk_bool_t prepared;
+
+ uint64_t bytes_out;
+ uint64_t bytes_in;
+
+ //unsigned connected:1;
+ void* mainThreadId[1];
+
+ char *description;
+
+ tnet_transport_cb_f callback;
+ const void* callback_data;
+
+ /* TLS certs */
+ struct {
+ char* ca;
+ char* pvk;
+ char* pbk;
+ tsk_bool_t enabled;
+ tsk_bool_t verify; // whether to verify client/server certificate
+ struct ssl_ctx_st *ctx_client;
+ struct ssl_ctx_st *ctx_server;
+ }tls;
+
+ /* DTLS */
+ struct{
+ tsk_bool_t enabled;
+ tsk_bool_t activated;
+ tsk_bool_t use_srtp;
+ struct ssl_ctx_st *ctx;
+ tnet_fingerprint_t fingerprints[TNET_DTLS_HASH_TYPE_MAX];
+ }dtls;
+
+ /* PROXY */
+ struct {
+ tsk_bool_t auto_detect;
+ struct tnet_proxyinfo_s* info; // manually set value
+ }
+ proxy;
+}
+tnet_transport_t;
+
+tsk_object_t* tnet_transport_context_create();
+TINYNET_API tnet_transport_t* tnet_transport_create(const char* host, tnet_port_t port, tnet_socket_type_t type, const char* description);
+TINYNET_API tnet_transport_t* tnet_transport_create_2(tnet_socket_t *master, const char* description);
+tnet_transport_event_t* tnet_transport_event_create(tnet_transport_event_type_t type, const void* callback_data, tnet_fd_t fd);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_transport_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_transport_event_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_transport_context_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_SERVER_H */
+
diff --git a/tinyNET/src/tnet_transport_cfsocket.c b/tinyNET/src/tnet_transport_cfsocket.c
new file mode 100644
index 0000000..4115b22
--- /dev/null
+++ b/tinyNET/src/tnet_transport_cfsocket.c
@@ -0,0 +1,1380 @@
+/*
+ * Copyright (C) 2010-2011 Mamadou Diop.
+ *
+ * Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+ * Original Author: Laurent Etiemble <laurent.etiemble(at)gmail.com>
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+
+/**@file tnet_transport_cfsocket.c
+ * @brief Network transport layer using CFSocket. Used for iOS devices.
+ *
+ * @author Laurent Etiemble <laurent(dot)etiemble(at)gmail(DOT)com>
+ * @author Mamadou Diop <diopmamadou(at)doubango(DOT)org>
+ */
+
+#include "tnet_transport.h"
+#include "tnet_proxy_plugin.h"
+#include "tnet_proxydetect.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+#include "tsk_thread.h"
+#include "tsk_buffer.h"
+#include "tsk_safeobj.h"
+
+#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
+
+
+#ifdef __OBJC__
+#import <Foundation/Foundation.h>
+#endif /* __OBJC__ */
+#import <Security/Security.h>
+#import <Security/SecureTransport.h>
+#import <CFNetwork/CFNetwork.h>
+
+#if !defined(TNET_MAX_FDS)
+# define TNET_MAX_FDS FD_SETSIZE
+#endif
+#define TNET_BUFFER_STREAM_MIN_SIZE 1024
+
+/*== Socket description ==*/
+typedef struct transport_socket_xs
+{
+ tnet_fd_t fd;
+ tsk_bool_t owner;
+ tsk_bool_t readable;
+ tsk_bool_t writable;
+ tsk_bool_t paused;
+ tsk_bool_t is_client;
+
+ tnet_proxy_node_t *proxy_node;
+ tnet_proxyinfo_t* proxy_info;
+ tsk_bool_t proxy_handshacking_completed;
+ tsk_bool_t proxy_handshacking_started;
+
+ char* dst_host;
+ tnet_port_t dst_port;
+
+ tnet_socket_type_t type;
+
+ CFSocketRef cf_socket;
+ CFReadStreamRef cf_read_stream;
+ CFWriteStreamRef cf_write_stream;
+ CFRunLoopSourceRef cf_run_loop_source;
+}
+transport_socket_xt;
+
+/*== Transport context structure definition ==*/
+typedef struct transport_context_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_size_t count;
+ transport_socket_xt* sockets[TNET_MAX_FDS];
+
+ CFRunLoopRef cf_run_loop;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+transport_context_t;
+
+static int recvData(tnet_transport_t *transport, transport_socket_xt* active_socket);
+static const transport_socket_xt* getSocket(transport_context_t *context, tnet_fd_t fd);
+int removeSocket(transport_socket_xt *value, transport_context_t *context);
+static int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client);
+static int addSocket2(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client, const char* dst_host, tnet_port_t dst_port, struct tnet_proxyinfo_s* proxy_info);
+static int removeSocketAtIndex(int index, transport_context_t *context);
+static int wrapSocket(tnet_transport_t *transport, transport_socket_xt *sock);
+static int enableSSL(tnet_transport_t *transport, transport_socket_xt *sock);
+static int startProxyHandshaking(tnet_transport_t *transport, transport_socket_xt *sock);
+
+static BOOL isTrusted(tnet_transport_t *transport, id cfStream, BOOL bReadStream)
+{
+ BOOL bTrusted = NO;
+ SecTrustRef trust = NULL;
+ OSStatus status = 0;
+ SecTrustResultType result;
+ SecCertificateRef certArray[2] = { NULL, NULL };
+ CFArrayRef refCertArray = NULL;
+ CFIndex certArrayCount = 0;
+
+ trust = bReadStream
+ ? (SecTrustRef)CFReadStreamCopyProperty((CFReadStreamRef)cfStream, kCFStreamPropertySSLPeerTrust)
+ : (SecTrustRef)CFWriteStreamCopyProperty((CFWriteStreamRef)cfStream, kCFStreamPropertySSLPeerTrust);
+ if (!trust) {
+ TSK_DEBUG_ERROR("Failed to get SecTrustRef object from '%s' stream", bReadStream ? "read" : "write");
+ goto bail;
+ }
+
+ NSString *caName = NULL, *pbName = NULL;
+
+ if (!tsk_strnullORempty(transport->tls.ca)) {
+ caName = [[[NSString stringWithCString:transport->tls.ca encoding: NSUTF8StringEncoding] lastPathComponent] stringByDeletingPathExtension];
+ }
+ if (!tsk_strnullORempty(transport->tls.pbk)) {
+ pbName = [[[NSString stringWithCString:transport->tls.pbk encoding: NSUTF8StringEncoding] lastPathComponent] stringByDeletingPathExtension];
+ }
+ TSK_DEBUG_INFO("SSL::isTrusted(ca=%s, pb=%s)", [caName UTF8String], [pbName UTF8String]);
+
+ if (caName) {
+ NSString *caPath = [[NSBundle mainBundle] pathForResource:caName ofType:@"der"];
+ if (![[NSFileManager defaultManager] fileExistsAtPath:caPath]) {
+ TSK_DEBUG_WARN("Cannot find SSL CA file '%s.der'", [caPath UTF8String]);
+ }
+ else {
+ NSData *certData = [[NSData alloc] initWithContentsOfFile:caPath];
+ CFDataRef certDataRef = (CFDataRef)certData;
+ SecCertificateRef cert = certDataRef ? SecCertificateCreateWithData(NULL, certDataRef) : NULL;
+ [certData release];
+ if (!cert) {
+ TSK_DEBUG_WARN("Cannot create SecCertificateRef object from '%s' file", [caPath UTF8String]);
+ }
+ else {
+ TSK_DEBUG_INFO("Using SecCertificateRef object created from '%s' for SSL validation", [caPath UTF8String]);
+ certArray[certArrayCount++] = cert;
+ }
+ }
+ }
+ if (pbName) {
+ NSString *pbPath = [[NSBundle mainBundle] pathForResource:pbName ofType:@"der"];
+ if (![[NSFileManager defaultManager] fileExistsAtPath:pbPath]) {
+ TSK_DEBUG_WARN("Cannot find SSL PUB file '%s.der'", [pbPath UTF8String]);
+ }
+ else {
+ NSData *certData = [[NSData alloc] initWithContentsOfFile:pbPath];
+ CFDataRef certDataRef = (CFDataRef)certData;
+ SecCertificateRef cert = certDataRef ? SecCertificateCreateWithData(NULL, certDataRef) : NULL;
+ [certData release];
+ if (!cert) {
+ TSK_DEBUG_WARN("Cannot create SecCertificateRef object from '%s' file", [pbPath UTF8String]);
+ }
+ else {
+ TSK_DEBUG_INFO("Using SecCertificateRef object created from '%s' for SSL validation", [pbPath UTF8String]);
+ certArray[certArrayCount++] = cert;
+ }
+ }
+ }
+ if (certArrayCount > 0) {
+ refCertArray = CFArrayCreate(NULL, (void *)certArray, certArrayCount, NULL);
+ }
+ status = SecTrustSetAnchorCertificates(trust, refCertArray);
+ if (status != noErr) {
+ TSK_DEBUG_ERROR("SecTrustSetAnchorCertificates failed with error code = %d", (int)status);
+ goto bail;
+ }
+ status = SecTrustSetAnchorCertificatesOnly(trust, YES);
+ if (status != noErr) {
+ TSK_DEBUG_ERROR("SecTrustSetAnchorCertificatesOnly failed with error code = %d", (int)status);
+ goto bail;
+ }
+ status = SecTrustEvaluate(trust, &result);
+ if (status != noErr) {
+ TSK_DEBUG_ERROR("SecTrustEvaluate failed with error code = %d", (int)status);
+ goto bail;
+ }
+ bTrusted = (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified);
+ TSK_DEBUG_INFO("SecTrustEvaluate result = %d", result);
+
+bail:
+ CFRelease(trust);
+ CFRelease(refCertArray);
+ return bTrusted;
+}
+
+
+static int recvData(tnet_transport_t *transport, transport_socket_xt* active_socket)
+{
+ int ret;
+ if(!transport || !transport->context || !active_socket){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ void* buffer = tsk_null;
+ tsk_size_t len = 0;
+ struct sockaddr_storage remote_addr = {0};
+
+ /* check whether the socket is paused or not */
+ if (active_socket->paused) {
+ TSK_DEBUG_INFO("Socket is paused");
+ goto bail;
+ }
+
+ tsk_bool_t is_stream = TNET_SOCKET_TYPE_IS_STREAM(active_socket->type);
+
+ if (tnet_ioctlt(active_socket->fd, FIONREAD, &len) < 0) {
+ TNET_PRINT_LAST_ERROR("ioctl() failed");
+ goto bail;
+ }
+
+ if (!len) {
+ // probably incoming connection
+ if (is_stream && !active_socket->is_client) {
+ tnet_fd_t fd;
+ if ((fd = accept(active_socket->fd, tsk_null, tsk_null)) != TNET_INVALID_SOCKET) {
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT(fd=%d)", transport->description, fd);
+ addSocket(fd, transport->master->type, transport, tsk_true, tsk_false);
+ TSK_RUNNABLE_ENQUEUE(transport, event_accepted, transport->callback_data, fd);
+ goto bail;
+ }
+ }
+
+ if (is_stream && CFReadStreamHasBytesAvailable(active_socket->cf_read_stream)) {
+ if ((buffer = tsk_calloc(TNET_BUFFER_STREAM_MIN_SIZE, sizeof(uint8_t)))) {
+ len = CFReadStreamRead(active_socket->cf_read_stream, buffer, (CFIndex)TNET_BUFFER_STREAM_MIN_SIZE);
+ ret = (int)len;
+ }
+ }
+
+ if (ret <= 0) {
+ TSK_DEBUG_WARN("ioctl() returned zero for fd=%d", active_socket->fd);
+ goto bail;
+ }
+ }
+
+ if (len && !buffer) {
+ if(!(buffer = tsk_calloc(len, sizeof(uint8_t)))){
+ TSK_DEBUG_ERROR("calloc(%zu) failed", len);
+ goto bail;
+ }
+
+ // Receive the waiting data
+ if (is_stream) {
+ ret = tnet_getpeername(active_socket->fd, &remote_addr);
+ if (active_socket->cf_read_stream) {
+ ret = (int)CFReadStreamRead(active_socket->cf_read_stream, buffer, (CFIndex)len);
+ }
+ else {
+ ret = tnet_sockfd_recv(active_socket->fd, buffer, len, 0);
+ }
+ }
+ else {
+ ret = tnet_sockfd_recvfrom(active_socket->fd, buffer, len, 0, (struct sockaddr*)&remote_addr);
+ }
+ }
+
+
+ if(ret < 0){
+ removeSocket(active_socket, transport->context);
+ TNET_PRINT_LAST_ERROR("recv/recvfrom have failed.");
+ goto bail;
+ }
+
+ if ((len != (tsk_size_t)ret) && len) {
+ len = (tsk_size_t)ret;
+ }
+
+ if (!active_socket->proxy_handshacking_completed && active_socket->proxy_handshacking_started && active_socket->proxy_node && active_socket->proxy_info) {
+ void* handshaking_data_ptr = tsk_null;
+ tsk_size_t handshaking_data_size = 0;
+ TSK_DEBUG_INFO("Proxy handshaking data:%.*s", (int)len, buffer);
+
+ // handle incoming hadshaking data
+ if ((ret = tnet_proxy_node_set_handshaking_data(active_socket->proxy_node, buffer, len)) != 0) {
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ removeSocket(active_socket, transport->context);
+ goto bail;
+ }
+ // pull handshaking data
+ ret = tnet_proxy_node_get_handshaking_pending_data(active_socket->proxy_node, &handshaking_data_ptr, &handshaking_data_size);
+ if (ret == 0 && handshaking_data_ptr && handshaking_data_size) {
+ // send handshaking data
+ tsk_size_t sent = tnet_transport_send(transport, active_socket->fd, handshaking_data_ptr, handshaking_data_size);
+ ret = (sent == handshaking_data_size) ? 0 : -1;
+ }
+ // free handshaking data
+ TSK_FREE(handshaking_data_ptr);
+ // check if handshaking completed
+ ret = tnet_proxy_node_get_handshaking_completed(active_socket->proxy_node, &active_socket->proxy_handshacking_completed);
+ if (active_socket->proxy_handshacking_completed) {
+ if (TNET_SOCKET_TYPE_IS_TLS(transport->type) && !TNET_SOCKET_TYPE_IS_TLS(active_socket->type)) {
+ // Upgrade the socket type from TCP to TLS and send SSL handshaking
+ TNET_SOCKET_TYPE_UNSET(active_socket->type, TCP);
+ TNET_SOCKET_TYPE_SET(active_socket->type, TLS);
+ if ((ret = enableSSL(transport, active_socket)) != 0) {
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ removeSocket(active_socket, transport->context);
+ goto bail;
+ }
+ }
+ TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, active_socket->fd);
+ }
+ goto bail; // do not forward the data to the end-user
+ }
+
+ if (len && buffer) {
+ tnet_transport_event_t* e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd);
+ if (e && buffer && len) {
+ e->data = buffer; buffer = NULL;
+ e->size = len;
+ e->remote_addr = remote_addr;
+
+ TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
+ }
+ }
+
+bail:
+ TSK_FREE(buffer);
+ return 0;
+}
+
+int tnet_transport_add_socket_2(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t* tlsHandle, const char* dst_host, tnet_port_t dst_port, struct tnet_proxyinfo_s* proxy_info)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t* context;
+ int ret = -1;
+ (void)(tlsHandle);
+
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return ret;
+ }
+
+ if (!(context = (transport_context_t*)transport->context)) {
+ TSK_DEBUG_ERROR("Invalid context.");
+ return -2;
+ }
+
+ if(TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)){
+ transport->tls.enabled = 1;
+ }
+
+ if ((ret = addSocket2(fd, type, transport, take_ownership, isClient, dst_host, dst_port, proxy_info))) {
+ TSK_DEBUG_ERROR("Failed to add new Socket.");
+ return ret;
+ }
+
+ if (context->cf_run_loop) {
+ // Signal the run-loop
+ CFRunLoopWakeUp(context->cf_run_loop);
+ }
+
+ return 0;
+}
+
+int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t* tlsHandle)
+{
+ static tnet_proxyinfo_t* __proxy_info_null = tsk_null;
+ static const char* __dst_host_null = tsk_null;
+ static tnet_port_t __dst_port_zero = 0;
+ return tnet_transport_add_socket_2(handle, fd, type, take_ownership, isClient, tlsHandle, __dst_host_null, __dst_port_zero, __proxy_info_null);
+}
+
+int tnet_transport_pause_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tsk_bool_t pause){
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ transport_socket_xt* socket;
+
+ if(!transport || !(context = (transport_context_t *)transport->context)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if((socket = (transport_socket_xt*)getSocket(context, fd))){
+ socket->paused = pause;
+ }
+ else {
+ TSK_DEBUG_WARN("Failed to find socket with fd=%d", (int)fd);
+ }
+
+ return 0;
+}
+
+/* Remove socket */
+int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_t *fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+
+ if (!transport || !fd) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ TSK_DEBUG_INFO("Removing socket %d", *fd);
+
+ if (!(context = (transport_context_t*)transport->context)) {
+ TSK_DEBUG_ERROR("Invalid context.");
+ return -2;
+ }
+
+ for(i=0; i<context->count; ++i) {
+ if (context->sockets[i]->fd == *fd) {
+ removeSocketAtIndex((int)i, context);
+ found = tsk_true;
+ *fd = TNET_INVALID_FD;
+ break;
+ }
+ }
+
+ if (found && context->cf_run_loop) {
+ // Signal the run-loop
+ CFRunLoopWakeUp(context->cf_run_loop);
+ return 0;
+ }
+
+ // ...
+
+ return -1;
+}
+
+tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t from, const void* buf, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ int numberOfBytesSent = 0;
+
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid transport handle.");
+ goto bail;
+ }
+
+ const transport_socket_xt* sock = getSocket(transport->context, from);
+ if (sock && sock->cf_write_stream && TNET_SOCKET_TYPE_IS_STREAM(sock->type) && sock->cf_write_stream) {
+ int sent = 0, to_send;
+ const uint8_t* buff_ptr = (const uint8_t*)buf;
+ // on iOS when TLS is enabled sending more than 1024 bytes could fails
+ static const int max_size_to_send = 1024;
+
+ to_send = (int)TSK_MIN(max_size_to_send, size);
+
+ if (CFWriteStreamGetStatus(sock->cf_write_stream) == kCFStreamStatusNotOpen) {
+ if(!CFWriteStreamOpen(sock->cf_write_stream)){
+ TSK_DEBUG_ERROR("CFWriteStreamOpen() failed");
+ return numberOfBytesSent;
+ }
+ }
+ if (CFReadStreamGetStatus(sock->cf_read_stream) == kCFStreamStatusNotOpen) {
+ if(!CFReadStreamOpen(sock->cf_read_stream)){
+ TSK_DEBUG_ERROR("CFReadStreamOpen() failed");
+ return numberOfBytesSent;
+ }
+ }
+ while (to_send > 0 && (sent = (int)CFWriteStreamWrite(sock->cf_write_stream, &buff_ptr[numberOfBytesSent], (CFIndex) to_send)) > 0) {
+ numberOfBytesSent += sent;
+ to_send = (int)TSK_MIN(max_size_to_send, (size - numberOfBytesSent));
+ }
+ if(sent < 0){
+ TNET_PRINT_LAST_ERROR("Send have failed");
+ goto bail;
+ }
+ } else {
+ if ((numberOfBytesSent = (int)send(from, buf, size, 0)) < size) {
+ TNET_PRINT_LAST_ERROR("Send have failed");
+ goto bail;
+ }
+ }
+
+bail:
+ return numberOfBytesSent;
+}
+
+tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void* buf, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ int numberOfBytesSent = 0, ret;
+
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid server handle");
+ goto bail;
+ }
+
+ if (!TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)) {
+ TSK_DEBUG_ERROR("In order to use sendto you must use an udp transport");
+ goto bail;
+ }
+
+ while (numberOfBytesSent < size && (ret = (int)sendto(from, buf, size, 0, to, tnet_get_sockaddr_size(to))) >= 0) {
+ numberOfBytesSent += ret;
+ }
+ if (numberOfBytesSent < size) {
+ if (tnet_geterrno() == TNET_ERROR_BROKENPIPE) {
+ TSK_DEBUG_INFO("UDP socket with fd=%d returned EPIPE...alerting the sender with 'event_brokenpipe' event", from);
+ TSK_RUNNABLE_ENQUEUE(transport, event_brokenpipe, transport->callback_data, from);
+ }
+ else {
+ TNET_PRINT_LAST_ERROR("sendto(fd=%d) have failed", from);
+ }
+ }
+
+bail:
+ return numberOfBytesSent;
+}
+
+int tnet_transport_have_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return 0;
+ }
+
+ return (getSocket((transport_context_t*)transport->context, fd) != 0);
+}
+
+const tnet_tls_socket_handle_t* tnet_transport_get_tlshandle(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
+ // not using openssl
+ return tsk_null;
+}
+
+/*== Get socket ==*/
+static const transport_socket_xt* getSocket(transport_context_t *context, tnet_fd_t fd)
+{
+ tsk_size_t i;
+ transport_socket_xt* ret = tsk_null;
+
+ if (context) {
+ tsk_safeobj_lock(context);
+ for(i=0; i<context->count; i++) {
+ if (context->sockets[i]->fd == fd) {
+ ret = context->sockets[i];
+ break;
+ }
+ }
+ tsk_safeobj_unlock(context);
+ }
+
+ return ret;
+}
+static const transport_socket_xt* getSocketByStream(transport_context_t *context, void* cf_stream)
+{
+ tsk_size_t i;
+ transport_socket_xt* ret = tsk_null;
+
+ if (context) {
+ tsk_safeobj_lock(context);
+ for(i=0; i<context->count; i++) {
+ if (context->sockets[i]->cf_read_stream == cf_stream || context->sockets[i]->cf_write_stream == cf_stream) {
+ ret = context->sockets[i];
+ break;
+ }
+ }
+ tsk_safeobj_unlock(context);
+ }
+
+ return ret;
+}
+
+/*== Add new socket ==*/
+
+int addSocket2(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client , const char* dst_host, tnet_port_t dst_port, struct tnet_proxyinfo_s* proxy_info) {
+ transport_context_t *context = transport?transport->context:0;
+ if (context) {
+ transport_socket_xt *sock = tsk_calloc(1, sizeof(transport_socket_xt));
+ sock->fd = fd;
+ sock->type = type;
+ sock->owner = take_ownership;
+ sock->is_client = is_client;
+ sock->dst_host = tsk_strdup(dst_host);
+ sock->dst_port = dst_port;
+ if (dst_host && dst_port && tnet_proxyinfo_is_valid(proxy_info)) {
+ sock->proxy_info = tsk_object_ref(proxy_info);
+ }
+
+ if (!sock) {
+ TSK_DEBUG_ERROR("Failed to allocate socket");
+ return -1;
+ }
+
+ tsk_safeobj_lock(context);
+ wrapSocket(transport, sock);
+ context->sockets[context->count] = sock;
+ context->count++;
+
+ tsk_safeobj_unlock(context);
+
+ TSK_DEBUG_INFO("Socket added");
+
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Context is Null.");
+ return -1;
+ }
+}
+
+int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client)
+{
+ static tnet_proxyinfo_t* __proxy_info_null = tsk_null;
+ static const char* __dst_host_null = tsk_null;
+ static tnet_port_t __dst_port_zero = 0;
+ return addSocket2(fd, type, transport, take_ownership, is_client, __dst_host_null, __dst_port_zero, __proxy_info_null);
+}
+
+/*== Remove socket ==*/
+int removeSocketAtIndex(int index, transport_context_t *context)
+{
+ int i;
+
+ tsk_safeobj_lock(context);
+
+ if (index < (int)context->count) {
+ transport_socket_xt *sock = context->sockets[index];
+ tnet_fd_t fd = sock->fd;
+
+ // Remove from runloop
+ if (context->cf_run_loop && sock->cf_run_loop_source) {
+ CFRunLoopRemoveSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopCommonModes);
+ CFRelease(sock->cf_run_loop_source), sock->cf_run_loop_source = NULL;
+ }
+
+ // Invalidate CFSocket
+ if (sock->cf_socket) {
+ if (CFSocketIsValid(sock->cf_socket)) {
+ CFSocketInvalidate(sock->cf_socket);
+ }
+ CFRelease(sock->cf_socket);
+ sock->cf_socket = NULL;
+ }
+
+ // Close and free write stream
+ if (sock->cf_write_stream) {
+ if (CFWriteStreamGetStatus(sock->cf_write_stream) != kCFStreamStatusClosed) {
+ CFWriteStreamClose(sock->cf_write_stream);
+ }
+ CFRelease(sock->cf_write_stream);
+ sock->cf_write_stream = NULL;
+ }
+
+ // Close and free read stream
+ if (sock->cf_read_stream) {
+ if (CFReadStreamGetStatus(sock->cf_read_stream) != kCFStreamStatusClosed) {
+ CFReadStreamClose(sock->cf_read_stream);
+ }
+ CFRelease(sock->cf_read_stream);
+ sock->cf_read_stream = NULL;
+ }
+
+ // Close the socket if we are the owner.
+ if (sock->owner) {
+ tnet_sockfd_close(&(sock->fd));
+ }
+
+ TSK_FREE(sock->dst_host);
+ TSK_OBJECT_SAFE_FREE(sock->proxy_node);
+ TSK_OBJECT_SAFE_FREE(sock->proxy_info);
+ TSK_FREE(sock);
+
+ for (i = index ; i<context->count-1; ++i) {
+ context->sockets[i] = context->sockets[i+1];
+ }
+
+ context->sockets[context->count-1] = tsk_null;
+ context->count--;
+
+ TSK_DEBUG_INFO("Socket removed: %d", fd);
+ }
+
+ tsk_safeobj_unlock(context);
+
+ return 0;
+}
+
+int removeSocket(transport_socket_xt *value, transport_context_t *context)
+{
+ int i;
+
+ tsk_safeobj_lock(context);
+
+ for(i = 0; i < context->count; i++) {
+ transport_socket_xt *sock = context->sockets[i];
+ if (sock == value) {
+ removeSocketAtIndex(i, context);
+ break;
+ }
+ }
+
+ tsk_safeobj_unlock(context);
+
+ return 0;
+}
+
+int tnet_transport_stop(tnet_transport_t *transport)
+{
+ int ret;
+ transport_context_t *context;
+
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ context = transport->context;
+
+ if ((ret = tsk_runnable_stop(TSK_RUNNABLE(transport)))) {
+ return ret;
+ }
+
+ if(transport->mainThreadId[0]){
+ if (context && context->cf_run_loop) {
+ // Signal the run-loop
+ CFRunLoopWakeUp(context->cf_run_loop);
+ }
+ return tsk_thread_join(transport->mainThreadId);
+ }
+ else { // already stopped
+ return 0;
+ }
+}
+
+int tnet_transport_prepare(tnet_transport_t *transport)
+{
+ int ret = -1;
+ transport_context_t *context;
+
+ if (!transport || !(context = transport->context)) {
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+
+ if (transport->prepared) {
+ TSK_DEBUG_ERROR("Transport already prepared.");
+ return -2;
+ }
+
+ /* Prepare master */
+ if(!transport->master){
+ if((transport->master = tnet_socket_create(transport->local_host, transport->req_local_port, transport->type))){
+ tsk_strupdate(&transport->local_ip, transport->master->ip);
+ transport->bind_local_port = transport->master->port;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create master socket");
+ return -3;
+ }
+ }
+
+ /* Start listening */
+ if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) {
+ if ((ret = tnet_sockfd_listen(transport->master->fd, TNET_MAX_FDS))) {
+ TNET_PRINT_LAST_ERROR("listen have failed.");
+ goto bail;
+ }
+ }
+
+ /* Add the master socket to the context. */
+ // don't take ownership: will be closed by the dtor() when refCount==0
+ // otherwise will be cosed twice: dtor() and removeSocket
+ if ((ret = addSocket(transport->master->fd, transport->master->type, transport, tsk_false, tsk_false))) {
+ TSK_DEBUG_ERROR("Failed to add master socket");
+ goto bail;
+ }
+
+ transport->prepared = tsk_true;
+
+bail:
+ return ret;
+}
+
+int tnet_transport_unprepare(tnet_transport_t *transport){
+ transport_context_t *context;
+
+ if(!transport || !(context = transport->context)){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+
+ if(!transport->prepared){
+ return 0;
+ }
+
+ transport->prepared = tsk_false;
+
+ while(context->count){
+ removeSocketAtIndex(0, context); // safe
+ }
+
+ // destroy master as it has been closed by removeSocket()
+ TSK_OBJECT_SAFE_FREE(transport->master);
+
+ return 0;
+}
+
+void __CFReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo) {
+ // Extract the context
+ tnet_transport_t *transport = (tnet_transport_t *) clientCallBackInfo;
+ transport_context_t *context = transport->context;
+
+ /* lock context */
+ tsk_safeobj_lock(context);
+
+ // Extract the native socket
+ CFDataRef data = CFReadStreamCopyProperty(stream, kCFStreamPropertySocketNativeHandle);
+ transport_socket_xt *sock = tsk_null;
+ if(data){
+ CFSocketNativeHandle fd;
+ CFDataGetBytes(data, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8*) &fd);
+ CFRelease(data);
+ sock = (transport_socket_xt *) getSocket(context, fd);
+ } else if (eventType == kCFStreamEventErrorOccurred) { // this event returns null data
+ sock = (transport_socket_xt *) getSocketByStream(context, stream);
+ }
+
+ if(!sock) {
+ goto bail;
+ }
+
+ switch(eventType) {
+ case kCFStreamEventOpenCompleted:
+ {
+ TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> kCFStreamEventOpenCompleted(fd=%d)", sock->fd);
+#if 0
+ // Check SSL certificates
+ if (TNET_SOCKET_TYPE_IS_TLS(sock->type) && transport->tls.verify) {
+ if (!isTrusted(transport, (__bridge id)stream, YES/*YES read stream*/)) {
+ TSK_DEBUG_ERROR("Remote SSL certs not trusted...closing the write stream");
+ TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, sock->fd);
+ removeSocket(sock, context);
+ break;
+ }
+ }
+#endif
+ // Set "readable" flag
+ if (!sock->readable) {
+ sock->readable = tsk_true;
+ if (sock->writable) {
+ if (!sock->proxy_info || sock->proxy_handshacking_completed) {
+ // no proxy or handshaking not done yet
+ TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, sock->fd);
+ }
+ else if (sock->proxy_info && !sock->proxy_handshacking_started) {
+ // proxy handshaking not done yet
+ sock->proxy_handshacking_started = tsk_true;
+ startProxyHandshaking(transport, sock);
+ }
+ }
+ }
+ break;
+ }
+ case kCFStreamEventEndEncountered:
+ {
+ TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> kCFStreamEventEndEncountered(fd=%d)", sock->fd);
+ TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, sock->fd);
+ removeSocket(sock, context);
+ break;
+ }
+ case kCFStreamEventHasBytesAvailable:
+ {
+ recvData(transport, sock);
+ break;
+ }
+ case kCFStreamEventErrorOccurred:
+ {
+ // Get the error code
+ CFErrorRef error = CFReadStreamCopyError(stream);
+ if (error) {
+ TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> Error=%lu -> %s, fd=%d, status=%ld", CFErrorGetCode(error), CFStringGetCStringPtr(CFErrorGetDomain(error), kCFStringEncodingUTF8), sock->fd, CFReadStreamGetStatus(stream));
+ CFRelease(error);
+ }
+
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, sock->fd);
+ removeSocket(sock, context);
+ break;
+ }
+ default:
+ {
+ // Not Implemented
+ TSK_DEBUG_WARN("Not implemented");
+ break;
+ }
+ }
+
+ /* unlock context */
+bail:
+ tsk_safeobj_unlock(context);
+}
+
+void __CFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo) {
+ // Extract the context
+ tnet_transport_t *transport = (tnet_transport_t *) clientCallBackInfo;
+ transport_context_t *context = transport->context;
+
+ /* lock context */
+ tsk_safeobj_lock(context);
+
+ // Extract the native socket
+ CFDataRef data = CFWriteStreamCopyProperty(stream, kCFStreamPropertySocketNativeHandle);
+ transport_socket_xt *sock = tsk_null;
+ if(data){
+ CFSocketNativeHandle fd;
+ CFDataGetBytes(data, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8*) &fd);
+ CFRelease(data);
+ sock = (transport_socket_xt *) getSocket(context, fd);
+ } else if (eventType == kCFStreamEventErrorOccurred) { // this event returns null data
+ sock = (transport_socket_xt *) getSocketByStream(context, stream);
+ }
+
+ if(!sock) {
+ goto bail;
+ }
+
+ switch(eventType) {
+ case kCFStreamEventOpenCompleted:
+ {
+ TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> kCFStreamEventOpenCompleted(fd=%d)", sock->fd);
+ // still not connected, see kCFStreamEventCanAcceptBytes
+ break;
+ }
+ case kCFStreamEventCanAcceptBytes:
+ {
+ // To avoid blocking, call this function only if CFWriteStreamCanAcceptBytes returns true or after the stream’s client (set with CFWriteStreamSetClient) is notified of a kCFStreamEventCanAcceptBytes event.
+ TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> kCFStreamEventCanAcceptBytes(fd=%d)", sock->fd);
+ // Check SSL certificates
+ if (TNET_SOCKET_TYPE_IS_TLS(sock->type) && transport->tls.verify) {
+ if (!isTrusted(transport, (__bridge id)stream, FALSE/*NOT read stream*/)) {
+ TSK_DEBUG_ERROR("Remote SSL certs not trusted...closing the write stream");
+ removeSocket(sock, context);
+ break;
+ }
+ }
+ // Set "writable" flag
+ if (!sock->writable) {
+ sock->writable = tsk_true;
+ if (sock->readable) {
+ if (!sock->proxy_info || sock->proxy_handshacking_completed) {
+ // no proxy or handshaking not done yet
+ TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, sock->fd);
+ }
+ else if (sock->proxy_info && !sock->proxy_handshacking_started) {
+ // proxy handshaking not done yet
+ sock->proxy_handshacking_started = tsk_true;
+ startProxyHandshaking(transport, sock);
+ }
+ }
+ }
+ break;
+ }
+ case kCFStreamEventEndEncountered:
+ {
+ TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> kCFStreamEventEndEncountered(fd=%d)", sock->fd);
+ TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, sock->fd);
+ removeSocket(sock, context);
+ break;
+ }
+ case kCFStreamEventErrorOccurred:
+ {
+ // Get the error code
+ CFErrorRef error = CFWriteStreamCopyError(stream);
+ if (error) {
+ TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> Error=%lu -> %s, fd=%d", CFErrorGetCode(error), CFStringGetCStringPtr(CFErrorGetDomain(error), kCFStringEncodingUTF8), sock->fd);
+ CFRelease(error);
+ }
+
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, sock->fd);
+ removeSocket(sock, context);
+ break;
+ }
+ default:
+ {
+ // Not Implemented
+ TSK_DEBUG_ERROR("Not implemented");
+ break;
+ }
+ }
+
+ /* unlock context */
+bail:
+ tsk_safeobj_unlock(context);
+}
+
+void __CFSocketCallBack(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) {
+ // Extract the context
+ tnet_transport_t *transport = (tnet_transport_t *) info;
+ transport_context_t *context = transport->context;
+
+ // Extract the native socket
+ int fd = CFSocketGetNative(s);
+ transport_socket_xt *sock = (transport_socket_xt *) getSocket(context, fd);
+ if(!sock) goto bail;
+
+ /* lock context */
+ tsk_safeobj_lock(context);
+
+ switch (callbackType) {
+ case kCFSocketReadCallBack:
+ {
+ recvData(transport, sock);
+ break;
+ }
+ case kCFSocketAcceptCallBack:
+ case kCFSocketConnectCallBack:
+ case kCFSocketWriteCallBack:
+ {
+ TSK_DEBUG_INFO("__CFSocketCallBack(fd=%d), callbackType=%lu", sock->fd, callbackType);
+ wrapSocket(transport, sock);
+ break;
+ }
+ case kCFSocketDataCallBack:
+ {
+ if (data) {
+ const UInt8 *ptr = CFDataGetBytePtr((CFDataRef)data);
+ int len = (int)CFDataGetLength((CFDataRef)data);
+ if (ptr && len > 0) {
+ tnet_transport_event_t* e = tnet_transport_event_create(event_data, transport->callback_data, sock->fd);
+ if (e) {
+ e->data = tsk_malloc(len);
+ if (e->data) {
+ memcpy(e->data, ptr, len);
+ e->size = len;
+ }
+ struct sockaddr* address_ = (struct sockaddr*)CFDataGetBytePtr(address);
+ memcpy(&e->remote_addr, address_, tnet_get_sockaddr_size(address_));
+ TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ {
+ // Not Implemented
+ TSK_DEBUG_ERROR("Not implemented");
+ break;
+ }
+ }
+
+ /* unlock context */
+bail:
+ tsk_safeobj_unlock(context);
+}
+
+
+
+int wrapSocket(tnet_transport_t *transport, transport_socket_xt *sock)
+{
+ transport_context_t *context;
+ int ret;
+ tsk_bool_t should_open_streams = tsk_false;
+ if (!transport || !(context = transport->context) || !sock) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // If the socket is already wrapped in a CFSocket or mainthead not started yet then return
+ if (!context->cf_run_loop) {
+ return 0;
+ }
+
+ // Put a reference to the transport context
+ const CFSocketContext socket_context = { 0, transport, NULL, NULL, NULL };
+
+ // Wrap socket and listen to events
+ if (!sock->cf_socket && !sock->cf_read_stream && !sock->cf_write_stream) {
+ sock->cf_socket = CFSocketCreateWithNative(kCFAllocatorDefault,
+ sock->fd,
+ kCFSocketReadCallBack | kCFSocketConnectCallBack | kCFSocketWriteCallBack | kCFSocketAcceptCallBack | kCFSocketDataCallBack,
+ &__CFSocketCallBack,
+ &socket_context);
+
+ // Don't close the socket if the CFSocket is invalidated
+ CFOptionFlags flags = CFSocketGetSocketFlags(sock->cf_socket);
+ flags = flags & ~kCFSocketCloseOnInvalidate;
+ CFSocketSetSocketFlags(sock->cf_socket, flags);
+
+ // Create a new RunLoopSource and register it with the main thread RunLoop
+ sock->cf_run_loop_source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sock->cf_socket, 0);
+ CFRunLoopAddSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopCommonModes);
+ }
+
+ if (TNET_SOCKET_TYPE_IS_DGRAM(sock->type)) {
+ // Nothing to do
+
+ } else if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) {
+ if (!sock->cf_read_stream && !sock->cf_write_stream) {
+ // Create a pair of streams (read/write) from the socket
+ CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock->fd, &sock->cf_read_stream, &sock->cf_write_stream);
+
+ // Don't close underlying socket
+ CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
+ CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
+
+ // Mark the stream for VoIP usage
+ CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
+ CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
+
+ // Setup a context for the streams
+ CFStreamClientContext streamContext = { 0, transport, NULL, NULL, NULL };
+
+ // Set the client callback for the stream
+ CFReadStreamSetClient(sock->cf_read_stream,
+ kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
+ &__CFReadStreamClientCallBack,
+ &streamContext);
+ CFWriteStreamSetClient(sock->cf_write_stream,
+ kCFStreamEventOpenCompleted | kCFStreamEventErrorOccurred | kCFStreamEventCanAcceptBytes |kCFStreamEventEndEncountered,
+ &__CFWriteStreamClientCallBack,
+ &streamContext);
+
+ if (TNET_SOCKET_TYPE_IS_TLS(sock->type)) {
+ if ((ret = enableSSL(transport, sock)) != 0) {
+ return ret;
+ }
+ }
+
+ // Enroll streams in the run-loop
+ CFReadStreamScheduleWithRunLoop(sock->cf_read_stream, context->cf_run_loop, kCFRunLoopCommonModes);
+ CFWriteStreamScheduleWithRunLoop(sock->cf_write_stream, context->cf_run_loop, kCFRunLoopCommonModes);
+ }
+
+ // Open streams only if ready (otherwise, fails on iOS8)
+ if (tnet_sockfd_waitUntilReadable(sock->fd, 1) == 0 || tnet_sockfd_waitUntilWritable(sock->fd, 1) == 0) {
+ // switch from cf_socket to streams
+ if (sock->cf_run_loop_source) {
+ CFRunLoopRemoveSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopCommonModes);
+ CFRelease(sock->cf_run_loop_source), sock->cf_run_loop_source = NULL;
+ }
+ if (sock->cf_socket) {
+ CFSocketInvalidate(sock->cf_socket);
+ CFRelease(sock->cf_socket);
+ sock->cf_socket = NULL;
+ }
+
+ should_open_streams = tsk_true;
+ }
+ }
+
+ // Proxy
+ if (sock->proxy_info) {
+ if (sock->proxy_node && sock->proxy_node->type != sock->proxy_info->type) {
+ TSK_OBJECT_SAFE_FREE(sock->proxy_node);
+ }
+ if (!sock->proxy_node && !(sock->proxy_node = tnet_proxy_node_create(sock->proxy_info->type))) {
+ TSK_DEBUG_ERROR("Failed to create proxy node");
+ return -1;
+ }
+ tnet_proxy_node_configure(sock->proxy_node,
+ TNET_PROXY_SET_DEST_ADDRESS(sock->dst_host, sock->dst_port),
+ TNET_PROXY_SET_PROXY_ADDRESS(sock->proxy_info->hostname, sock->proxy_info->port),
+ TNET_PROXY_NODE_SET_IPV6(TNET_SOCKET_TYPE_IS_IPV6(sock->type)),
+ TNET_PROXY_SET_CREDENTIALS(sock->proxy_info->username, sock->proxy_info->password),
+ TNET_PROXY_SET_CFSTREAM(sock->cf_read_stream, sock->cf_write_stream),
+ TNET_PROXY_SET_SOCKET(sock->fd, sock->type),
+ TNET_PROXY_NODE_SET_NULL());
+ }
+
+ // Open streams
+ if (should_open_streams) {
+ if (!CFReadStreamOpen(sock->cf_read_stream)) {
+ CFStreamStatus status = CFReadStreamGetStatus(sock->cf_read_stream);
+ if (status != kCFStreamStatusOpen && status != kCFStreamStatusOpening && status != kCFStreamStatusReading) {
+ TSK_DEBUG_ERROR("CFReadStreamOpen(fd=%d) failed with status=%ld", sock->fd, status);
+ return -1;
+ }
+ TSK_DEBUG_INFO("CFReadStreamOpen(fd=%d) returned with status=%ld", sock->fd, status);
+ }
+ if (!CFWriteStreamOpen(sock->cf_write_stream)) {
+ CFStreamStatus status = CFWriteStreamGetStatus(sock->cf_write_stream);
+ if (status != kCFStreamStatusOpen && status != kCFStreamStatusOpening && status != kCFStreamStatusWriting) {
+ TSK_DEBUG_ERROR("CFWriteStreamOpen(fd=%d) failed with status=%ld", sock->fd, status);
+ return -1;
+ }
+ TSK_DEBUG_INFO("CFWriteStreamOpen(fd=%d) returned with status=%ld", sock->fd, status);
+ }
+ }
+
+ return 0;
+}
+
+static int enableSSL(tnet_transport_t *transport, transport_socket_xt *sock)
+{
+ if (!transport || !sock || !TNET_SOCKET_TYPE_IS_TLS(sock->type)) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (sock->cf_write_stream && sock->cf_read_stream) {
+ CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
+ CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
+ CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
+ CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
+
+ CFMutableDictionaryRef settings = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+#if (__IPHONE_OS_VERSION_MIN_REQUIRED < 40000) // @Deprecated
+ CFDictionaryAddValue(settings, kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue);
+ CFDictionaryAddValue(settings, kCFStreamSSLAllowsAnyRoot, kCFBooleanTrue); // self-signed? - deprecated
+#endif
+ // Set "kCFStreamSSLValidatesCertificateChain" to false to accept self-signed certs. The validation will be done manually using "isTrusted()" to check cert matching if "verify" option is enabled.
+ CFDictionaryAddValue(settings, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
+ CFDictionaryAddValue(settings, kCFStreamSSLIsServer, sock->is_client ? kCFBooleanFalse : kCFBooleanTrue);
+ CFDictionaryAddValue(settings, kCFStreamSSLPeerName, kCFNull);
+
+ // Set the SSL settings
+ CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertySSLSettings, settings);
+ CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertySSLSettings, settings);
+
+ CFRelease(settings);
+ }
+ return 0;
+}
+
+static int startProxyHandshaking(tnet_transport_t *transport, transport_socket_xt *sock)
+{
+ transport_context_t *context;
+ int ret;
+ void* handshaking_data_ptr = tsk_null;
+ tsk_size_t handshaking_data_size = 0;
+
+ if (!transport || !(context = transport->context) || !sock || !sock->proxy_info || !sock->proxy_node) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // start handshaking
+ if ((ret = tnet_proxy_node_start_handshaking(sock->proxy_node)) != 0) {
+ return ret;
+ }
+ // pull handshaking data
+ ret = tnet_proxy_node_get_handshaking_pending_data(sock->proxy_node, &handshaking_data_ptr, &handshaking_data_size);
+ if (ret == 0 && handshaking_data_ptr && handshaking_data_size) {
+ // send handshaking data
+ tsk_size_t sent = tnet_transport_send(transport, sock->fd, handshaking_data_ptr, handshaking_data_size);
+ ret = (sent == handshaking_data_size) ? 0 : -1;
+ }
+ // free handshaking data
+ TSK_FREE(handshaking_data_ptr);
+ // check if handshaking completed
+ tnet_proxy_node_get_handshaking_completed(sock->proxy_node, &sock->proxy_handshacking_completed);
+
+ return ret;
+}
+
+/*=== Main thread */
+void *tnet_transport_mainthread(void *param)
+{
+ tnet_transport_t *transport = param;
+ transport_context_t *context = transport->context;
+ int i;
+
+ /* check whether the transport is already prepared */
+ if (!transport->prepared) {
+ TSK_DEBUG_ERROR("Transport must be prepared before strating.");
+ goto bail;
+ }
+
+ TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d} with fd {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->fd);
+
+ // Set the RunLoop of the context
+ context->cf_run_loop = CFRunLoopGetCurrent();
+ CFRetain(context->cf_run_loop);
+ // Wrap sockets now that the runloop is defined
+ tsk_safeobj_lock(context);
+ for (i = 0; i < context->count; ++i) {
+ wrapSocket(transport, context->sockets[i]);
+ }
+ tsk_safeobj_unlock(context);
+
+ while(TSK_RUNNABLE(transport)->running) {
+ // Give some time to process sources
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0, false);
+
+ if (!TSK_RUNNABLE(transport)->running) {
+ goto bail;
+ }
+ }
+
+ // Remove all the sockets, streams and sources from the run loop
+ tsk_safeobj_lock(context);
+ for(i = 0; i < context->count; i++) {
+ transport_context_t *context = transport->context;
+ transport_socket_xt *sock = context->sockets[i];
+
+ if (!sock) {
+ continue;
+ }
+ if (sock->cf_run_loop_source) {
+ CFRunLoopRemoveSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopDefaultMode);
+ }
+ if (sock->cf_read_stream) {
+ //CFReadStreamClose(sock->cf_read_stream);
+ CFReadStreamUnscheduleFromRunLoop(sock->cf_read_stream, context->cf_run_loop, kCFRunLoopDefaultMode);
+ }
+ if (sock->cf_write_stream) {
+ //CFWriteStreamClose(sock->cf_write_stream);
+ CFWriteStreamUnscheduleFromRunLoop(sock->cf_write_stream, context->cf_run_loop, kCFRunLoopDefaultMode);
+ }
+ }
+ tsk_safeobj_unlock(context);
+
+
+bail:
+ TSK_DEBUG_INFO("Stopped [%s] server with IP {%s} on port {%d}...", transport->description, transport->master->ip, transport->master->port);
+ if(context->cf_run_loop){
+ CFRelease(context->cf_run_loop);
+ context->cf_run_loop = NULL;
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
+void* tnet_transport_context_create()
+{
+ return tsk_object_new(tnet_transport_context_def_t);
+}
+
+
+//=================================================================================================
+// Transport context object definition
+//
+static tsk_object_t* transport_context_ctor(tsk_object_t * self, va_list * app)
+{
+ transport_context_t *context = self;
+ if (context) {
+ tsk_safeobj_init(context);
+ }
+ return self;
+}
+
+static tsk_object_t* transport_context_dtor(tsk_object_t * self)
+{
+ transport_context_t *context = self;
+ if (context) {
+ while(context->count) {
+ removeSocketAtIndex(0, context);
+ }
+ tsk_safeobj_deinit(context);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_transport_context_def_s =
+{
+ sizeof(transport_context_t),
+ transport_context_ctor,
+ transport_context_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_transport_context_def_t = &tnet_transport_context_def_s;
+
+#endif /* HAVE_POLL_H */
diff --git a/tinyNET/src/tnet_transport_poll.c b/tinyNET/src/tnet_transport_poll.c
new file mode 100644
index 0000000..7ee6509
--- /dev/null
+++ b/tinyNET/src/tnet_transport_poll.c
@@ -0,0 +1,913 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop
+* Copyright (C) 2012-2013 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_transport_poll.c
+ * @brief Network transport layer using polling.
+ *
+ */
+#include "tnet_transport.h"
+#include "tnet_proxy_plugin.h"
+#include "tnet_proxydetect.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+#include "tsk_thread.h"
+#include "tsk_buffer.h"
+#include "tsk_safeobj.h"
+
+#if USE_POLL && !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
+
+#include "tnet_poll.h"
+
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h> /* http://www.freebsd.org/doc/en/books/porters-handbook/porting-versions.html */
+#endif
+
+#if !defined(TNET_MAX_FDS)
+# if defined(FD_SETSIZE)
+# define TNET_MAX_FDS FD_SETSIZE
+# else
+# define TNET_MAX_FDS (0xFFFF - 1)
+# endif
+#endif
+
+/*== Socket description ==*/
+typedef struct transport_socket_xs
+{
+ tnet_fd_t fd;
+ tsk_bool_t owner;
+ tsk_bool_t connected;
+ tsk_bool_t paused;
+
+ tnet_socket_type_t type;
+ tnet_tls_socket_handle_t* tlshandle;
+}
+transport_socket_xt;
+
+/*== Transport context structure definition ==*/
+typedef struct transport_context_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_size_t count;
+ tnet_fd_t pipeW;
+ tnet_fd_t pipeR;
+ tnet_pollfd_t ufds[TNET_MAX_FDS];
+ transport_socket_xt* sockets[TNET_MAX_FDS];
+ tsk_bool_t polling; // whether we are poll()ing
+
+ TSK_DECLARE_SAFEOBJ;
+}
+transport_context_t;
+
+static transport_socket_xt* getSocket(transport_context_t *context, tnet_fd_t fd);
+static int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client, tnet_tls_socket_handle_t* tlsHandle);
+static int removeSocket(int index, transport_context_t *context);
+
+
+int tnet_transport_add_socket_2(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t* tlsHandle, const char* dst_host, tnet_port_t dst_port, struct tnet_proxyinfo_s* proxy_info)
+{
+ // TODO: support for web-proxies not added yet
+ (void)(dst_host);
+ (void)(dst_port);
+ (void)(proxy_info);
+ return tnet_transport_add_socket(handle, fd, type, take_ownership, isClient, tlsHandle);
+}
+
+int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t* tlsHandle)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t* context;
+ static char c = '\0';
+ int ret = -1;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return ret;
+ }
+
+ if(!(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid context.");
+ return -2;
+ }
+
+ if(TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)){
+ transport->tls.enabled = 1;
+ }
+
+ if((ret = addSocket(fd, type, transport, take_ownership, isClient, tlsHandle))){
+ TSK_DEBUG_ERROR("Failed to add new Socket.");
+ return ret;
+ }
+
+ // signal
+ if(context->pipeW && (TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started)){
+ if((ret = write(context->pipeW, &c, 1)) > 0){
+ TSK_DEBUG_INFO("Socket added (external call) %d", fd);
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to add new Socket.");
+ return ret;
+ }
+ } else {
+ TSK_DEBUG_INFO("pipeW (write site) not initialized yet.");
+ return 0; //Will be taken when mainthead start
+ }
+}
+
+int tnet_transport_pause_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tsk_bool_t pause)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ transport_socket_xt* socket;
+
+ if(!transport || !(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if((socket = getSocket(context, fd))){
+ socket->paused = pause;
+ }
+ else{
+ TSK_DEBUG_WARN("Socket does not exist in this context");
+ }
+ return 0;
+}
+
+/* Remove socket */
+int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_t *pfd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ int ret = -1;
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+ tnet_fd_t fd = *pfd;
+
+ TSK_DEBUG_INFO("Removing socket %d", fd);
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return ret;
+ }
+
+ if(!(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid context.");
+ return -2;
+ }
+
+ tsk_safeobj_lock(context);
+
+ for(i=0; i<context->count; i++){
+ if(context->sockets[i]->fd == fd){
+ tsk_bool_t self_ref = (&context->sockets[i]->fd == pfd);
+ removeSocket(i, context); // sockets[i] will be destroyed
+ found = tsk_true;
+ TSK_RUNNABLE_ENQUEUE(transport, event_removed, transport->callback_data, fd);
+ if(!self_ref){ // if self_ref then, pfd no longer valid after removeSocket()
+ *pfd = TNET_INVALID_FD;
+ }
+ break;
+ }
+ }
+
+ tsk_safeobj_unlock(context);
+
+ if(found){
+ /* Signal */
+ static char c = '\0';
+ ret = write(context->pipeW, &c, 1);
+ return (ret > 0 ? 0 : ret);
+ }
+
+ // ...
+
+ return -1;
+}
+
+
+tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t from, const void* buf, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ int numberOfBytesSent = 0;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid transport handle.");
+ goto bail;
+ }
+
+ if(transport->tls.enabled){
+ const transport_socket_xt* socket = getSocket(transport->context, from);
+ if(socket && socket->tlshandle){
+ if(!tnet_tls_socket_send(socket->tlshandle, buf, size)){
+ numberOfBytesSent = size;
+ }
+ else{
+ numberOfBytesSent = 0;
+ }
+ goto bail;
+ }
+ }
+ else if((numberOfBytesSent = tnet_sockfd_send(from, buf, size, 0)) <= 0){
+ TNET_PRINT_LAST_ERROR("send have failed.");
+
+ //tnet_sockfd_close(&from);
+ goto bail;
+ }
+
+bail:
+ transport->bytes_out += numberOfBytesSent;
+ return numberOfBytesSent;
+}
+
+tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void* buf, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ int numberOfBytesSent = 0;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ goto bail;
+ }
+
+ if(!TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)){
+ TSK_DEBUG_ERROR("In order to use sendto() you must use an udp transport.");
+ goto bail;
+ }
+
+ if((numberOfBytesSent = tnet_sockfd_sendto(from, to, buf, size)) <= 0){
+ TNET_PRINT_LAST_ERROR("sendto have failed.");
+ goto bail;
+ }
+
+bail:
+ transport->bytes_out += numberOfBytesSent;
+ return numberOfBytesSent;
+}
+
+int tnet_transport_have_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return 0;
+ }
+
+ return (getSocket((transport_context_t*)transport->context, fd) != 0);
+}
+
+const tnet_tls_socket_handle_t* tnet_transport_get_tlshandle(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ const transport_socket_xt *socket;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
+
+ if((socket = getSocket((transport_context_t*)transport->context, fd))){
+ return socket->tlshandle;
+ }
+ return 0;
+}
+
+
+/*== Get socket ==*/
+static transport_socket_xt* getSocket(transport_context_t *context, tnet_fd_t fd)
+{
+ tsk_size_t i;
+ transport_socket_xt* ret = 0;
+
+ if(context){
+ tsk_safeobj_lock(context);
+ for(i=0; i<context->count; i++){
+ if(context->sockets[i]->fd == fd){
+ ret = context->sockets[i];
+ break;
+ }
+ }
+ tsk_safeobj_unlock(context);
+ }
+
+ return ret;
+}
+
+/*== Add new socket ==*/
+int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client, tnet_tls_socket_handle_t* tlsHandle)
+{
+ transport_context_t *context = transport?transport->context:0;
+ if(context){
+ transport_socket_xt *sock = tsk_calloc(1, sizeof(transport_socket_xt));
+ sock->fd = fd;
+ sock->type = type;
+ sock->owner = take_ownership;
+
+ if((TNET_SOCKET_TYPE_IS_TLS(sock->type) || TNET_SOCKET_TYPE_IS_WSS(sock->type)) && transport->tls.enabled){
+ if(tlsHandle){
+ sock->tlshandle = tsk_object_ref(tlsHandle);
+ }
+ else{
+#if HAVE_OPENSSL
+ sock->tlshandle = tnet_tls_socket_create(sock->fd, is_client ? transport->tls.ctx_client : transport->tls.ctx_server);
+#endif
+ }
+ }
+
+ tsk_safeobj_lock(context);
+
+ context->ufds[context->count].fd = fd;
+ context->ufds[context->count].events = (fd == context->pipeR) ? TNET_POLLIN : (TNET_POLLIN | TNET_POLLNVAL | TNET_POLLERR);
+ if(TNET_SOCKET_TYPE_IS_STREAM(sock->type)){
+ context->ufds[context->count].events |= TNET_POLLOUT; // emulate WinSock2 FD_CONNECT event
+ }
+ context->ufds[context->count].revents = 0;
+ context->sockets[context->count] = sock;
+
+ context->count++;
+
+ tsk_safeobj_unlock(context);
+
+ TSK_DEBUG_INFO("Socket added[%s]: fd=%d, tail.count=%d", transport->description, fd, context->count);
+
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Context is Null.");
+ return -1;
+ }
+}
+
+/*== change connection state ==*/
+/*
+static void setConnected(tnet_fd_t fd, transport_context_t *context, int connected)
+{
+ tsk_size_t i;
+
+ for(i=0; i<context->count; i++)
+ {
+ if(context->sockets[i]->fd == fd){
+ context->sockets[i]->connected = connected;
+ }
+ }
+}
+*/
+
+/*== Remove socket ==*/
+int removeSocket(int index, transport_context_t *context)
+{
+ int i;
+
+ tsk_safeobj_lock(context);
+
+ if(index < (int)context->count){
+ /* Close the socket if we are the owner. */
+ TSK_DEBUG_INFO("Socket to remove: fd=%d, index=%d, tail.count=%d", context->sockets[index]->fd, index, context->count);
+ if(context->sockets[index]->owner){
+ // do not close the socket while it's being poll()ed
+ // http://stackoverflow.com/questions/5039608/poll-cant-detect-event-when-socket-is-closed-locally
+ if(context->polling){
+ TSK_DEBUG_INFO("RemoveSocket(fd=%d) has been requested but we are poll()ing the socket. ShutdownSocket(fd) called on the socket and we deferred the request.", context->sockets[index]->fd);
+ TSK_DEBUG_INFO("ShutdownSocket(fd=%d)", context->sockets[index]->fd);
+ tnet_sockfd_shutdown(context->sockets[index]->fd);
+ goto done;
+ }
+ tnet_sockfd_close(&(context->sockets[index]->fd));
+ }
+
+ /* Free tls context */
+ TSK_OBJECT_SAFE_FREE(context->sockets[index]->tlshandle);
+
+ // Free socket
+ TSK_FREE(context->sockets[index]);
+
+ for(i=index ; i<context->count-1; i++){
+ context->sockets[i] = context->sockets[i+1];
+ context->ufds[i] = context->ufds[i+1];
+ }
+
+ context->sockets[context->count-1] = tsk_null;
+ context->ufds[context->count-1].fd = TNET_INVALID_FD;
+ context->ufds[context->count-1].events = 0;
+ context->ufds[context->count-1].revents = 0;
+
+ context->count--;
+ }
+done:
+ tsk_safeobj_unlock(context);
+
+ return 0;
+}
+
+int tnet_transport_stop(tnet_transport_t *transport)
+{
+ int ret;
+ transport_context_t *context;
+
+ if(!transport){
+ return -1;
+ }
+
+ context = transport->context;
+
+ if((ret = tsk_runnable_stop(TSK_RUNNABLE(transport)))){
+ return ret;
+ }
+
+ if(context){
+ static char c = '\0';
+
+ // signal
+ tsk_safeobj_lock(context); // =>MUST
+ if(tnet_transport_have_socket(transport, context->pipeR)){ // to avoid SIGPIPE=> check that there is at least one reader
+ write(context->pipeW, &c, 1);
+ }
+ tsk_safeobj_unlock(context);
+ }
+
+ if(transport->mainThreadId[0]){
+ return tsk_thread_join(transport->mainThreadId);
+ }
+ else{
+ /* already soppped */
+ return 0;
+ }
+}
+
+int tnet_transport_prepare(tnet_transport_t *transport)
+{
+ int ret = -1;
+ transport_context_t *context;
+ tnet_fd_t pipes[2];
+
+ TSK_DEBUG_INFO("tnet_transport_prepare()");
+
+ if(!transport || !transport->context){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+ else{
+ context = transport->context;
+ }
+
+ if(transport->prepared){
+ TSK_DEBUG_ERROR("Transport already prepared.");
+ return -2;
+ }
+
+ /* Prepare master */
+ if(!transport->master){
+ if((transport->master = tnet_socket_create(transport->local_host, transport->req_local_port, transport->type))){
+ tsk_strupdate(&transport->local_ip, transport->master->ip);
+ transport->bind_local_port = transport->master->port;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create master socket");
+ return -3;
+ }
+ }
+
+ /* Start listening */
+ if(TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)){
+ if((ret = tnet_sockfd_listen(transport->master->fd, TNET_MAX_FDS))){
+ TNET_PRINT_LAST_ERROR("listen have failed.");
+ goto bail;
+ }
+ }
+
+ /* Create and add pipes to the fd_set */
+ if((ret = pipe(pipes))){
+ TNET_PRINT_LAST_ERROR("Failed to create new pipes.");
+ goto bail;
+ }
+
+ /* set both R and W sides */
+ context->pipeR = pipes[0];
+ context->pipeW = pipes[1];
+
+ /* add R side */
+ TSK_DEBUG_INFO("pipeR fd=%d, pipeW=%d", context->pipeR, context->pipeW);
+ if((ret = addSocket(context->pipeR, transport->master->type, transport, tsk_true, tsk_false, tsk_null))){
+ goto bail;
+ }
+
+ /* Add the master socket to the context. */
+ TSK_DEBUG_INFO("master fd=%d", transport->master->fd);
+ // don't take ownership: will be closed by the dctor() when refCount==0
+ // otherwise will be closed twice: dctor() and removeSocket()
+ if((ret = addSocket(transport->master->fd, transport->master->type, transport, tsk_false, tsk_false, tsk_null))){
+ TSK_DEBUG_ERROR("Failed to add master socket");
+ goto bail;
+ }
+
+ transport->prepared = tsk_true;
+
+bail:
+ return ret;
+}
+
+int tnet_transport_unprepare(tnet_transport_t *transport)
+{
+ //int ret = -1;
+ transport_context_t *context;
+
+ if(!transport || !transport->context){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+ else{
+ context = transport->context;
+ }
+
+ if(!transport->prepared){
+ return 0;
+ }
+
+ transport->prepared = tsk_false;
+
+ while(context->count){
+ removeSocket(0, context); // safe
+ }
+
+ /* reset both R and W sides */
+ if (context->pipeW != -1) {
+ if (close(context->pipeW)) {
+ TSK_DEBUG_ERROR("Failed to close pipeW:%d", context->pipeW);
+ }
+ context->pipeW = -1;
+ }
+ context->pipeR = -1;
+
+ // destroy master as it has been closed by removeSocket()
+ TSK_OBJECT_SAFE_FREE(transport->master);
+
+ return 0;
+}
+
+/*=== Main thread */
+void *tnet_transport_mainthread(void *param)
+{
+ tnet_transport_t *transport = param;
+ transport_context_t *context = transport->context;
+ int ret, status;
+ tsk_size_t i;
+ tsk_bool_t is_stream;
+ tnet_fd_t fd;
+
+ struct sockaddr_storage remote_addr = {0};
+ transport_socket_xt* active_socket;
+
+ /* check whether the transport is already prepared */
+ if(!transport->prepared){
+ TSK_DEBUG_ERROR("Transport must be prepared before strating.");
+ goto bail;
+ }
+
+ is_stream = TNET_SOCKET_TYPE_IS_STREAM(transport->master->type);
+
+ TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d} using fd {%d} with type {%d}...",
+ transport->description,
+ transport->master->ip,
+ transport->master->port,
+ transport->master->fd,
+ transport->master->type);
+
+ while(TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started){
+ context->polling = tsk_true;
+ ret = tnet_poll(context->ufds, context->count, -1);
+ context->polling = tsk_false;
+ if(ret < 0){
+ TNET_PRINT_LAST_ERROR("poll() have failed.");
+ goto bail;
+ }
+
+ if(!TSK_RUNNABLE(transport)->running && !TSK_RUNNABLE(transport)->started){
+ TSK_DEBUG_INFO("Stopping [%s] server with IP {%s} on port {%d} with type {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->type);
+ goto bail;
+ }
+
+ /* lock context */
+ tsk_safeobj_lock(context);
+
+ /* == == */
+ for(i=0; i<context->count; i++)
+ {
+ if(!context->ufds[i].revents){
+ continue;
+ }
+
+ // TSK_DEBUG_INFO("REVENTS(i=%d) = %d", i, context->ufds[i].revents);
+
+ if(context->ufds[i].fd == context->pipeR){
+ TSK_DEBUG_INFO("PipeR event = %d", context->ufds[i].revents);
+ if(context->ufds[i].revents & TNET_POLLIN){
+ static char __buffer[1024];
+ if(read(context->pipeR, __buffer, sizeof(__buffer)) < 0){
+ TNET_PRINT_LAST_ERROR("Failed to read from the Pipe");
+ }
+ }
+ else if(context->ufds[i].revents & TNET_POLLHUP){
+ TNET_PRINT_LAST_ERROR("Pipe Error");
+ goto bail;
+ }
+ context->ufds[i].revents = 0;
+ continue;
+ }
+
+ /* Get active event and socket */
+ active_socket = context->sockets[i];
+
+ /*================== TNET_POLLHUP ==================*/
+ if(context->ufds[i].revents & (TNET_POLLHUP)){
+ if(context->ufds[i].revents & TNET_POLLOUT){
+ TSK_DEBUG_INFO("POLLOUT and POLLHUP are exclusive");
+ }
+ else{
+ fd = active_socket->fd;
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLHUP(%d)", transport->description, fd);
+
+ tnet_transport_remove_socket(transport, &active_socket->fd);
+ TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, fd);
+ continue;
+ }
+ }
+
+ /*================== TNET_POLLERR ==================*/
+ if(context->ufds[i].revents & (TNET_POLLERR)){
+ fd = active_socket->fd;
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLERR(%d)", transport->description, fd);
+
+ tnet_transport_remove_socket(transport, &active_socket->fd);
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, fd);
+ continue;
+ }
+
+ /*================== TNET_POLLNVAL ==================*/
+ if(context->ufds[i].revents & (TNET_POLLNVAL)){
+ fd = active_socket->fd;
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLNVAL(%d)", transport->description, fd);
+
+ tnet_transport_remove_socket(transport, &active_socket->fd);
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, fd);
+ continue;
+ }
+
+ /*================== POLLIN ==================*/
+ if(context->ufds[i].revents & TNET_POLLIN)
+ {
+ tsk_size_t len = 0;
+ void* buffer = tsk_null;
+ tnet_transport_event_t* e;
+
+ // TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLIN(%d)", transport->description, active_socket->fd);
+
+ /* check whether the socket is paused or not */
+ if(active_socket->paused){
+ TSK_DEBUG_INFO("Socket is paused");
+ goto TNET_POLLIN_DONE;
+ }
+
+ /* Retrieve the amount of pending data.
+ * IMPORTANT: If you are using Symbian please update your SDK to the latest build (August 2009) to have 'FIONREAD'.
+ * This apply whatever you are using the 3rd or 5th edition.
+ * Download link: http://wiki.forum.nokia.com/index.php/Open_C/C%2B%2B_Release_History
+ */
+ ret = tnet_ioctlt(active_socket->fd, FIONREAD, &len);
+ if((ret < 0 || !len) && is_stream){
+ /* It's probably an incoming connection --> try to accept() it */
+ int listening = 0, remove_socket = 0;
+ socklen_t socklen = sizeof(listening);
+
+ TSK_DEBUG_INFO("ioctlt(%d), len=%u returned zero or failed", active_socket->fd, len);
+
+ // check if socket is listening
+ if(getsockopt(active_socket->fd, SOL_SOCKET, SO_ACCEPTCONN, &listening, &socklen) != 0){
+#if defined(BSD) /* old FreeBSD versions (and OSX up to Lion) do not support SO_ACCEPTCONN */
+ listening = 1;
+#else
+ TNET_PRINT_LAST_ERROR("getsockopt(SO_ACCEPTCONN, %d) failed\n", active_socket->fd);
+ /* not socket accepted -> no socket to remove */
+ goto TNET_POLLIN_DONE;
+#endif
+ }
+ if (listening){
+ if((fd = accept(active_socket->fd, tsk_null, tsk_null)) != TNET_INVALID_SOCKET){
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT(fd=%d)", transport->description, fd);
+ addSocket(fd, transport->master->type, transport, tsk_true, tsk_false, tsk_null);
+ TSK_RUNNABLE_ENQUEUE(transport, event_accepted, transport->callback_data, fd);
+ if(active_socket->tlshandle){
+ transport_socket_xt* tls_socket;
+ if((tls_socket = getSocket(context, fd))){
+ if(tnet_tls_socket_accept(tls_socket->tlshandle) != 0){
+ TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, fd);
+ tnet_transport_remove_socket(transport, &fd);
+ TNET_PRINT_LAST_ERROR("SSL_accept() failed");
+ continue;
+ }
+ }
+ }
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("accept(%d) failed", active_socket->fd);
+ remove_socket = 1;
+ }
+ }
+ else{
+ TSK_DEBUG_INFO("Closing socket with fd = %d because ioctlt() returned zero or failed", active_socket->fd);
+ remove_socket = 1;
+ }
+
+ if(remove_socket){
+ fd = active_socket->fd;
+ tnet_transport_remove_socket(transport, &active_socket->fd);
+ TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, fd);
+ continue;
+ }
+ goto TNET_POLLIN_DONE;
+ }
+
+ if(len <= 0){
+#if ANDROID
+ // workaround for indoona OSX which sends bodiless UDP packets
+ // vand Android requires to call recv() even if len is equal to zero
+ if(len == 0 && ret == 0){
+ static char __fake_buff[1];
+ ret = recv(active_socket->fd, __fake_buff, len, 0);
+ }
+#endif
+ goto TNET_POLLIN_DONE;
+ }
+
+ if (!(buffer = tsk_calloc(len, sizeof(uint8_t)))) {
+ TSK_DEBUG_ERROR("TSK_CALLOC FAILED");
+ goto TNET_POLLIN_DONE;
+ }
+
+ // Retrieve the remote address
+ if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) {
+ ret = tnet_getpeername(active_socket->fd, &remote_addr);
+ }
+
+ // Receive the waiting data
+ if (active_socket->tlshandle) {
+ int isEncrypted;
+ tsk_size_t tlslen = len;
+ if ((ret = tnet_tls_socket_recv(active_socket->tlshandle, &buffer, &tlslen, &isEncrypted)) == 0) {
+ if (isEncrypted) {
+ TSK_FREE(buffer);
+ goto TNET_POLLIN_DONE;
+ }
+ if (ret == 0) {
+ len = ret = tlslen;
+ }
+ }
+ }
+ else {
+ if (is_stream) {
+ ret = tnet_sockfd_recv(active_socket->fd, buffer, len, 0);
+ }
+ else {
+ ret = tnet_sockfd_recvfrom(active_socket->fd, buffer, len, 0, (struct sockaddr*)&remote_addr);
+ }
+ }
+
+ if(ret < 0){
+ TSK_FREE(buffer);
+ status = tnet_geterrno();
+ // do not remove the socket for i/o pending errors
+ if (status == TNET_ERROR_WOULDBLOCK || status == TNET_ERROR_INPROGRESS || status == TNET_ERROR_EAGAIN) {
+ TSK_DEBUG_WARN("recv returned error code:%d", status);
+ }
+ else {
+ TNET_PRINT_LAST_ERROR("recv/recvfrom have failed");
+ removeSocket(i, context);
+ }
+ goto TNET_POLLIN_DONE;
+ }
+
+ if((len != (tsk_size_t)ret) && len){
+ len = (tsk_size_t)ret;
+ // buffer = tsk_realloc(buffer, len);
+ }
+
+ if(len > 0){
+ transport->bytes_in += len;
+ e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd);
+ e->data = buffer, buffer = tsk_null;
+ e->size = len;
+ e->remote_addr = remote_addr;
+
+ TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
+ }
+ TSK_FREE(buffer);
+
+TNET_POLLIN_DONE:
+ /*context->ufds[i].revents &= ~TNET_POLLIN*/;
+ }
+
+
+ /*================== TNET_POLLOUT ==================*/
+ if(context->ufds[i].revents & TNET_POLLOUT){
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLOUT", transport->description);
+ if(!active_socket->connected){
+ active_socket->connected = tsk_true;
+ TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, active_socket->fd);
+ }
+ //else{
+ context->ufds[i].events &= ~TNET_POLLOUT;
+ //}
+ }
+
+
+ /*================== TNET_POLLPRI ==================*/
+ if(context->ufds[i].revents & TNET_POLLPRI){
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLPRI", transport->description);
+ }
+
+ context->ufds[i].revents = 0;
+ }/* for */
+
+done:
+ /* unlock context */
+ tsk_safeobj_unlock(context);
+
+ } /* while */
+
+bail:
+
+ TSK_DEBUG_INFO("Stopped [%s] server with IP {%s} on port {%d}", transport->description, transport->master->ip, transport->master->port);
+ return 0;
+}
+
+
+
+
+
+
+
+
+void* tnet_transport_context_create()
+{
+ return tsk_object_new(tnet_transport_context_def_t);
+}
+
+
+//=================================================================================================
+// Transport context object definition
+//
+static tsk_object_t* transport_context_ctor(tsk_object_t * self, va_list * app)
+{
+ transport_context_t *context = self;
+ if(context){
+ context->pipeR = context->pipeW = -1;
+ tsk_safeobj_init(context);
+ }
+ return self;
+}
+
+static tsk_object_t* transport_context_dtor(tsk_object_t * self)
+{
+ transport_context_t *context = self;
+ if(context){
+ while(context->count){
+ removeSocket(0, context);
+ }
+ tsk_safeobj_deinit(context);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_transport_context_def_s =
+{
+sizeof(transport_context_t),
+transport_context_ctor,
+transport_context_dtor,
+tsk_null,
+};
+const tsk_object_def_t *tnet_transport_context_def_t = &tnet_transport_context_def_s;
+
+#endif /* HAVE_POLL_H */
+
+
diff --git a/tinyNET/src/tnet_transport_win32.c b/tinyNET/src/tnet_transport_win32.c
new file mode 100644
index 0000000..6f7886f
--- /dev/null
+++ b/tinyNET/src/tnet_transport_win32.c
@@ -0,0 +1,840 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_transport_win32.c
+ * @brief Network transport layer for WIN32(XP/Vista/7) and WINCE(5.0 or higher) systems.
+ *
+ */
+#include "tnet_transport.h"
+#include "tnet_proxy_plugin.h"
+#include "tnet_proxydetect.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+#include "tsk_thread.h"
+#include "tsk_buffer.h"
+#include "tsk_safeobj.h"
+
+#if TNET_UNDER_WINDOWS && !TNET_USE_POLL
+
+/*== Socket description ==*/
+typedef struct transport_socket_xs
+{
+ tnet_fd_t fd;
+ unsigned owner : 1;
+ unsigned connected : 1;
+ unsigned paused : 1;
+
+ tnet_socket_type_t type;
+ tnet_tls_socket_handle_t* tlshandle;
+}
+transport_socket_xt;
+
+/*== Transport context structure definition ==*/
+typedef struct transport_context_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_size_t count;
+ WSAEVENT events[WSA_MAXIMUM_WAIT_EVENTS];
+ transport_socket_xt* sockets[WSA_MAXIMUM_WAIT_EVENTS];
+
+ TSK_DECLARE_SAFEOBJ;
+}
+transport_context_t;
+
+static transport_socket_xt* getSocket(transport_context_t *context, tnet_fd_t fd);
+static int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client, tnet_tls_socket_handle_t* tlsHandle);
+static int removeSocket(int index, transport_context_t *context);
+
+/* Checks if socket is connected */
+int tnet_transport_isconnected(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ tsk_size_t i;
+
+ if (!transport)
+ {
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return 0;
+ }
+
+ context = (transport_context_t*)transport->context;
+ for (i = 0; i < context->count; i++)
+ {
+ const transport_socket_xt* socket = context->sockets[i];
+ if (socket->fd == fd){
+ return socket->connected;
+ }
+ }
+
+ return 0;
+}
+
+int tnet_transport_have_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+
+ if (!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return 0;
+ }
+
+ return (getSocket((transport_context_t*)transport->context, fd) != 0);
+}
+
+const tnet_tls_socket_handle_t* tnet_transport_get_tlshandle(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_socket_xt *socket;
+
+ if (!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return 0;
+ }
+
+ if ((socket = getSocket((transport_context_t*)transport->context, fd))){
+ return socket->tlshandle;
+ }
+ return 0;
+}
+
+int tnet_transport_add_socket_2(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t* tlsHandle, const char* dst_host, tnet_port_t dst_port, struct tnet_proxyinfo_s* proxy_info)
+{
+ // TODO: support for web-proxies not added yet
+ (void)(dst_host);
+ (void)(dst_port);
+ (void)(proxy_info);
+ return tnet_transport_add_socket(handle, fd, type, take_ownership, isClient, tlsHandle);
+}
+
+/*
+* Add new socket to the watcher.
+*/
+int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t* tlsHandle)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t* context;
+ int ret = -1;
+
+ if (!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return ret;
+ }
+
+ if (!(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid context.");
+ return -2;
+ }
+
+ if (TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)){
+ transport->tls.enabled = tsk_true;
+ }
+
+ addSocket(fd, type, transport, take_ownership, isClient, tlsHandle);
+
+ if (WSAEventSelect(fd, context->events[context->count - 1], FD_ALL_EVENTS) == SOCKET_ERROR){
+ removeSocket((int)(context->count - 1), context);
+ TNET_PRINT_LAST_ERROR("WSAEventSelect have failed.");
+ return -1;
+ }
+
+ /* Signal if transport is running */
+ if (TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started){
+ if (WSASetEvent(context->events[0])){
+ TSK_DEBUG_INFO("New socket added to the network transport.");
+ return 0;
+ }
+ TSK_DEBUG_ERROR("Transport not started yet");
+ return -1;
+ }
+
+ TSK_DEBUG_INFO("Adding socket delayed");
+ return 0;
+}
+
+int tnet_transport_pause_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tsk_bool_t pause)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ transport_socket_xt* socket;
+
+ if (!transport || !(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if ((socket = getSocket(context, fd))){
+ socket->paused = pause;
+ }
+ else{
+ TSK_DEBUG_WARN("Socket does not exist in this context");
+ }
+ return 0;
+}
+
+/* Remove socket
+*/
+int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_t* fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ int ret = -1;
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+
+ if (!transport || !(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ for (i = 0; i < context->count; i++){
+ if (context->sockets[i]->fd == *fd){
+ removeSocket((int)i, context);
+ found = tsk_true;
+ TSK_RUNNABLE_ENQUEUE(transport, event_removed, transport->callback_data, *fd);
+ *fd = TNET_INVALID_FD;
+ break;
+ }
+ }
+
+ if (found){
+ /* Signal */
+ if (WSASetEvent(context->events[0])){
+ TSK_DEBUG_INFO("Old socket removed from the network transport.");
+ return 0;
+ }
+ }
+
+ // ...
+
+ return -1;
+}
+
+/*
+* Sends stream/dgram data to the remote peer (shall be previously connected using @tnet_transport_connectto).
+*/
+tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t from, const void* buf, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ int ret = -1;
+ tsk_size_t sent = 0;
+
+ if (!transport){
+ TSK_DEBUG_ERROR("Invalid transport handle.");
+ goto bail;
+ }
+
+ while (sent < size) {
+ int try_guard = 10;
+ if (transport->tls.enabled){
+ transport_socket_xt* socket = getSocket(transport->context, from);
+ if (socket && socket->tlshandle) {
+ if (tnet_tls_socket_send(socket->tlshandle, buf, size) == 0) {
+ sent = size;
+ }
+ else {
+ TSK_DEBUG_ERROR("Tring to use a socket without TLS handle to send data");
+ }
+ goto bail; // TLS do not retry
+ }
+ }
+ else {
+ WSABUF wsaBuffer;
+ DWORD numberOfBytesSent = 0;
+ wsaBuffer.buf = ((CHAR*)buf) + sent;
+ wsaBuffer.len = (ULONG)(size - sent);
+try_again:
+ if ((ret = WSASend(from, &wsaBuffer, 1, &numberOfBytesSent, 0, NULL, NULL)) == SOCKET_ERROR) {
+ ret = WSAGetLastError();
+ if (ret == WSA_IO_PENDING || ret == WSAEWOULDBLOCK) {
+ TSK_DEBUG_INFO("SendTCP() - WouldBlock. Retrying...");
+ if (try_guard--) {
+ tsk_thread_sleep(10);
+ goto try_again;
+ }
+ }
+ else {
+ TNET_PRINT_LAST_ERROR("WSASend have failed.");
+ goto bail;
+ }
+ }
+ else {
+ sent += numberOfBytesSent;
+ }
+ }
+ }
+
+bail:
+ transport->bytes_out += sent;
+ return sent;
+}
+
+/*
+* Sends dgarm to the specified destionation.
+*/
+tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void* buf, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ int numberOfBytesSent = 0;
+
+ if (!transport) {
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ goto bail;
+ }
+
+ if (!TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)) {
+ TSK_DEBUG_ERROR("In order to use sendto() you must use an udp transport.");
+ goto bail;
+ }
+
+ if ((numberOfBytesSent = tnet_sockfd_sendto(from, to, buf, size)) <= 0) {
+ TNET_PRINT_LAST_ERROR("sendto have failed.");
+ goto bail;
+ }
+
+bail:
+ transport->bytes_out += numberOfBytesSent;
+ return numberOfBytesSent;
+}
+
+
+
+
+
+
+
+
+/*== CAllback function to check if we should accept the new socket or not == */
+int CALLBACK AcceptCondFunc(LPWSABUF lpCallerId, LPWSABUF lpCallerData, LPQOS lpSQos, LPQOS lpGQos, LPWSABUF lpCalleeId, LPWSABUF lpCalleeData, GROUP FAR *Group, DWORD_PTR CallbackData)
+{
+ transport_context_t *context = (transport_context_t*)CallbackData;
+ return context->count < WSA_MAXIMUM_WAIT_EVENTS ? CF_ACCEPT : CF_REJECT;
+}
+
+/*== Get socket ==*/
+static transport_socket_xt* getSocket(transport_context_t *context, tnet_fd_t fd)
+{
+ tsk_size_t i;
+ transport_socket_xt* ret = 0;
+
+ if (context) {
+ tsk_safeobj_lock(context);
+ for (i = 0; i < context->count; i++) {
+ if (context->sockets[i]->fd == fd) {
+ ret = context->sockets[i];
+ break;
+ }
+ }
+ tsk_safeobj_unlock(context);
+ }
+
+ return ret;
+}
+
+/*== Add new socket ==*/
+static int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client, tnet_tls_socket_handle_t* tlsHandle)
+{
+ transport_context_t *context;
+
+ if (TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)) {
+#if !HAVE_OPENSSL
+ TSK_DEBUG_ERROR("Cannot create TLS socket: OpenSSL missing");
+ return -2;
+#endif
+ }
+
+ if ((context = transport ? transport->context : tsk_null)) {
+ transport_socket_xt *sock = tsk_calloc(1, sizeof(transport_socket_xt));
+ sock->fd = fd;
+ sock->type = type;
+ sock->owner = take_ownership ? 1 : 0;
+
+ if ((TNET_SOCKET_TYPE_IS_TLS(sock->type) || TNET_SOCKET_TYPE_IS_WSS(sock->type)) && transport->tls.enabled) {
+ if (tlsHandle) {
+ sock->tlshandle = tsk_object_ref(tlsHandle);
+ }
+ else{
+#if HAVE_OPENSSL
+ sock->tlshandle = tnet_tls_socket_create(sock->fd, is_client ? transport->tls.ctx_client : transport->tls.ctx_server);
+#endif
+ }
+ }
+
+ tsk_safeobj_lock(context);
+ context->events[context->count] = WSACreateEvent();
+ context->sockets[context->count] = sock;
+
+ context->count++;
+
+ TSK_DEBUG_INFO("Transport[%s] sockets count = %u", transport->description, context->count);
+
+ tsk_safeobj_unlock(context);
+
+ return 0;
+ }
+ else {
+ TSK_DEBUG_ERROR("Context is Null.");
+ return -1;
+ }
+ }
+
+/*== Remove socket ==*/
+static int removeSocket(int index, transport_context_t *context)
+{
+ tsk_size_t i;
+
+ tsk_safeobj_lock(context);
+
+ if (index < (int)context->count) {
+
+ /* Close the socket if we are the owner. */
+ if (context->sockets[index]->owner) {
+ tnet_sockfd_close(&(context->sockets[index]->fd));
+ }
+
+ /* Free tls context */
+ if (context->sockets[index]->tlshandle) {
+ TSK_OBJECT_SAFE_FREE(context->sockets[index]->tlshandle);
+ }
+ // Free socket
+ TSK_FREE(context->sockets[index]);
+
+ // Close event
+ WSACloseEvent(context->events[index]);
+
+ for (i = index; i < context->count - 1; i++) {
+ context->sockets[i] = context->sockets[i + 1];
+ context->events[i] = context->events[i + 1];
+ }
+
+ context->sockets[context->count - 1] = 0;
+ context->events[context->count - 1] = 0;
+
+ context->count--;
+ TSK_DEBUG_INFO("Transport sockets count = %u", context->count);
+ }
+
+ tsk_safeobj_unlock(context);
+
+ return 0;
+}
+
+/*=== stop all threads */
+int tnet_transport_stop(tnet_transport_t *transport)
+{
+ int ret;
+
+ if ((ret = tsk_runnable_stop(TSK_RUNNABLE(transport)))){
+ return ret;
+ }
+
+ if (transport->mainThreadId[0]){
+ WSASetEvent(((transport_context_t*)(transport->context))->events[0]);
+ return tsk_thread_join(transport->mainThreadId);
+ }
+ else{
+ /* already stoppped */
+ return 0;
+ }
+}
+
+
+int tnet_transport_prepare(tnet_transport_t *transport)
+{
+ int ret = -1;
+ transport_context_t *context;
+
+ if (!transport || !transport->context){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+ else{
+ context = transport->context;
+ }
+
+ if (transport->prepared){
+ TSK_DEBUG_ERROR("Transport already prepared.");
+ return -2;
+ }
+
+ /* Prepare master */
+ if (!transport->master){
+ if ((transport->master = tnet_socket_create(transport->local_host, transport->req_local_port, transport->type))){
+ tsk_strupdate(&transport->local_ip, transport->master->ip);
+ transport->bind_local_port = transport->master->port;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create master socket");
+ return -3;
+ }
+ }
+
+ /* Start listening */
+ if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) {
+ if ((ret = tnet_sockfd_listen(transport->master->fd, WSA_MAXIMUM_WAIT_EVENTS))) {
+ TNET_PRINT_LAST_ERROR("listen have failed.");
+ goto bail;
+ }
+ }
+
+ /* Add the master socket to the context. */
+ // don't take ownership: will be closed by the dctor() when refCount==0
+ // otherwise will be closed twice: dctor() and removeSocket()
+ if ((ret = addSocket(transport->master->fd, transport->master->type, transport, tsk_false, tsk_false, tsk_null))) {
+ TSK_DEBUG_ERROR("Failed to add master socket");
+ goto bail;
+ }
+
+ /* set events on master socket */
+ if ((ret = WSAEventSelect(transport->master->fd, context->events[context->count - 1], FD_ALL_EVENTS) == SOCKET_ERROR)) {
+ TNET_PRINT_LAST_ERROR("WSAEventSelect have failed.");
+ goto bail;
+ }
+
+ transport->prepared = tsk_true;
+
+bail:
+ return ret;
+}
+
+int tnet_transport_unprepare(tnet_transport_t *transport)
+{
+ int ret = -1;
+ transport_context_t *context;
+
+ if (!transport || !transport->context){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+ else{
+ context = transport->context;
+ }
+
+ if (!transport->prepared){
+ return 0;
+ }
+
+ transport->prepared = tsk_false;
+
+ while (context->count){
+ removeSocket(0, context); // safe
+ }
+ // destroy master as it has been close by removeSocket()
+ TSK_OBJECT_SAFE_FREE(transport->master);
+
+ return 0;
+}
+
+/*=== Main thread */
+void* TSK_STDCALL tnet_transport_mainthread(void *param)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)param;
+ transport_context_t *context = (transport_context_t*)transport->context;
+ DWORD evt;
+ WSANETWORKEVENTS networkEvents;
+ DWORD flags = 0;
+ int ret;
+
+ struct sockaddr_storage remote_addr = { 0 };
+ WSAEVENT active_event;
+ transport_socket_xt* active_socket;
+ int index;
+
+ TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d} with type {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->type);
+
+ while (TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started) {
+ /* Wait for multiple events */
+ if ((evt = WSAWaitForMultipleEvents((DWORD)context->count, context->events, FALSE, WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED) {
+ TNET_PRINT_LAST_ERROR("WSAWaitForMultipleEvents have failed.");
+ goto bail;
+ }
+
+ if (!TSK_RUNNABLE(transport)->running && !TSK_RUNNABLE(transport)->started) {
+ goto bail;
+ }
+
+ /* lock context */
+ tsk_safeobj_lock(context);
+
+ /* Get active event and socket */
+ index = (evt - WSA_WAIT_EVENT_0);
+ active_event = context->events[index];
+ if (!(active_socket = context->sockets[index])) {
+ goto done;
+ }
+
+ /* Get the network events flags */
+ if (WSAEnumNetworkEvents(active_socket->fd, active_event, &networkEvents) == SOCKET_ERROR) {
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ TNET_PRINT_LAST_ERROR("WSAEnumNetworkEvents have failed.");
+
+ tsk_safeobj_unlock(context);
+ goto bail;
+ }
+
+ /*================== FD_ACCEPT ==================*/
+ if (networkEvents.lNetworkEvents & FD_ACCEPT) {
+ tnet_fd_t fd;
+
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT", transport->description);
+
+ if (networkEvents.iErrorCode[FD_ACCEPT_BIT]) {
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ TNET_PRINT_LAST_ERROR("ACCEPT FAILED.");
+ goto done;
+ }
+
+ /* Accept the connection */
+ if ((fd = (tnet_fd_t)WSAAccept(active_socket->fd, NULL, NULL, AcceptCondFunc, (DWORD_PTR)context)) != INVALID_SOCKET) {
+ /* Add the new fd to the server context */
+ addSocket(fd, transport->master->type, transport, tsk_true, tsk_false, tsk_null);
+ if (active_socket->tlshandle) {
+ transport_socket_xt* tls_socket;
+ if ((tls_socket = getSocket(context, fd))) {
+ if (tnet_tls_socket_accept(tls_socket->tlshandle)) {
+ tnet_transport_remove_socket(transport, &fd);
+ TNET_PRINT_LAST_ERROR("SSL_accept() failed");
+ goto done;
+ }
+ }
+ }
+ if (WSAEventSelect(fd, context->events[context->count - 1], FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR) {
+ tnet_transport_remove_socket(transport, &fd);
+ TNET_PRINT_LAST_ERROR("WSAEventSelect() have failed.");
+ goto done;
+ }
+ TSK_RUNNABLE_ENQUEUE(transport, event_accepted, transport->callback_data, fd);
+ }
+ else {
+ TNET_PRINT_LAST_ERROR("ACCEPT FAILED.");
+ goto done;
+ }
+
+
+
+
+ }
+
+ /*================== FD_CONNECT ==================*/
+ if (networkEvents.lNetworkEvents & FD_CONNECT) {
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_CONNECT", transport->description);
+
+ if (networkEvents.iErrorCode[FD_CONNECT_BIT]) {
+ tnet_fd_t fd = active_socket->fd;
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, fd);
+ tnet_transport_remove_socket(transport, &fd);
+ TNET_PRINT_LAST_ERROR("CONNECT FAILED.");
+ goto done;
+ }
+ else {
+ TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, active_socket->fd);
+ active_socket->connected = 1;
+ }
+ }
+
+
+ /*================== FD_READ ==================*/
+ if (networkEvents.lNetworkEvents & FD_READ) {
+ DWORD readCount = 0;
+ WSABUF wsaBuffer;
+
+ /* TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_READ", transport->description); */
+
+ /* check whether the socket is paused or not */
+ if (active_socket->paused){
+ TSK_DEBUG_INFO("Socket is paused");
+ goto FD_READ_DONE;
+ }
+
+ if (networkEvents.iErrorCode[FD_READ_BIT]) {
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ TNET_PRINT_LAST_ERROR("READ FAILED.");
+ goto done;
+ }
+
+ /* Retrieve the amount of pending data */
+ if (tnet_ioctlt(active_socket->fd, FIONREAD, &(wsaBuffer.len)) < 0) {
+ TNET_PRINT_LAST_ERROR("IOCTLT FAILED.");
+ goto done;
+ }
+
+ if (!wsaBuffer.len) {
+ goto done;
+ }
+
+ /* Alloc data */
+ if (!(wsaBuffer.buf = tsk_calloc(wsaBuffer.len, sizeof(uint8_t)))) {
+ goto done;
+ }
+
+ /* Retrieve the remote address */
+ if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) {
+ ret = tnet_getpeername(active_socket->fd, &remote_addr);
+ }
+
+ /* Receive the waiting data. */
+ if (active_socket->tlshandle) {
+ int isEncrypted;
+ tsk_size_t len = wsaBuffer.len;
+ if (!(ret = tnet_tls_socket_recv(active_socket->tlshandle, &wsaBuffer.buf, &len, &isEncrypted))) {
+ if (isEncrypted) {
+ TSK_FREE(wsaBuffer.buf);
+ goto done;
+ }
+ wsaBuffer.len = (ULONG)len;
+ }
+ }
+ else {
+ if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) {
+ ret = WSARecv(active_socket->fd, &wsaBuffer, 1, &readCount, &flags, 0, 0);
+ }
+ else {
+ int len = sizeof(remote_addr);
+ ret = WSARecvFrom(active_socket->fd, &wsaBuffer, 1, &readCount, &flags,
+ (struct sockaddr*)&remote_addr, &len, 0, 0);
+ }
+ if (readCount < wsaBuffer.len) {
+ wsaBuffer.len = readCount;
+ /* wsaBuffer.buf = tsk_realloc(wsaBuffer.buf, readCount); */
+ }
+ }
+
+ if (ret) {
+ ret = WSAGetLastError();
+ if (ret == WSAEWOULDBLOCK) {
+ // Doesn't (always) mean congestion but... another thread is also poll()ing the FD. For example, when TURN session has a reference to the fd.
+ TSK_DEBUG_WARN("WSAEWOULDBLOCK error for READ SSESSION");
+ }
+ else if (ret == WSAECONNRESET && TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)) {
+ /* For DGRAM ==> The sent packet gernerated "ICMP Destination/Port unreachable" result. */
+ TSK_FREE(wsaBuffer.buf);
+ goto done; // ignore and retry.
+ }
+ else {
+ TSK_FREE(wsaBuffer.buf);
+
+ removeSocket(index, context);
+ TNET_PRINT_LAST_ERROR("WSARecv have failed.");
+ goto done;
+ }
+ }
+ else
+ {
+ tnet_transport_event_t* e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd);
+ transport->bytes_in += wsaBuffer.len;
+ e->data = wsaBuffer.buf;
+ e->size = wsaBuffer.len;
+ e->remote_addr = remote_addr;
+
+ TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
+ }
+ FD_READ_DONE:;
+ }
+
+
+
+
+ /*================== FD_WRITE ==================*/
+ if (networkEvents.lNetworkEvents & FD_WRITE) {
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_WRITE", transport->description);
+
+ if (networkEvents.iErrorCode[FD_WRITE_BIT]) {
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ TNET_PRINT_LAST_ERROR("WRITE FAILED.");
+ goto done;
+ }
+ }
+
+
+
+ /*================== FD_CLOSE ==================*/
+ if (networkEvents.lNetworkEvents & FD_CLOSE) {
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_CLOSE", transport->description);
+
+ TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, active_socket->fd);
+ removeSocket(index, context);
+ }
+
+ /* http://msdn.microsoft.com/en-us/library/ms741690(VS.85).aspx
+
+ The proper way to reset the state of an event object used with the WSAEventSelect function
+ is to pass the handle of the event object to the WSAEnumNetworkEvents function in the hEventObject parameter.
+ This will reset the event object and adjust the status of active FD events on the socket in an atomic fashion.
+ */
+ /* WSAResetEvent(active_event); <== DO NOT USE (see above) */
+
+ done:
+ /* unlock context */
+ tsk_safeobj_unlock(context);
+ } /* while(transport->running) */
+
+
+bail:
+
+ TSK_DEBUG_INFO("Stopped [%s] server with IP {%s} on port {%d} with type {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->type);
+ return tsk_null;
+}
+
+
+
+
+tsk_object_t* tnet_transport_context_create()
+{
+ return tsk_object_new(tnet_transport_context_def_t);
+}
+
+
+//=================================================================================================
+// Transport context object definition
+//
+static tsk_object_t* transport_context_ctor(tsk_object_t * self, va_list * app)
+{
+ transport_context_t *context = self;
+ if (context){
+ tsk_safeobj_init(context);
+ }
+ return self;
+}
+
+static tsk_object_t* transport_context_dtor(tsk_object_t * self)
+{
+ transport_context_t *context = self;
+ if (context) {
+ while (context->count) {
+ removeSocket(0, context);
+ }
+ tsk_safeobj_deinit(context);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_transport_context_def_s =
+{
+ sizeof(transport_context_t),
+ transport_context_ctor,
+ transport_context_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_transport_context_def_t = &tnet_transport_context_def_s;
+#endif /* TNET_UNDER_WINDOWS */
+
diff --git a/tinyNET/src/tnet_types.h b/tinyNET/src/tnet_types.h
new file mode 100644
index 0000000..f4b55e2
--- /dev/null
+++ b/tinyNET/src/tnet_types.h
@@ -0,0 +1,184 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_types.h
+ * @brief ????.
+ *
+ */
+#ifndef TNET_TYPES_H
+#define TNET_TYPES_H
+
+#include "tinynet_config.h"
+
+#if TNET_UNDER_WINDOWS
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# if !TNET_UNDER_WINDOWS_RT
+# include <iphlpapi.h>
+# endif
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/select.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# include <fcntl.h>
+# include <sys/ioctl.h>
+# include <unistd.h>
+# include <net/if.h>
+# if HAVE_IFADDRS_H
+# include <ifaddrs.h>
+# endif
+# if HAVE_POLL_H
+# include <poll.h>
+# endif /* HAVE_POLL_H */
+#endif
+
+#if defined(TNET_HAVE_SCTP)
+#include <netinet/sctp.h>
+#endif
+
+#include "tsk_errno.h"
+#include "tsk_list.h"
+
+TNET_BEGIN_DECLS
+
+#if !defined(TNET_FINGERPRINT_MAX)
+# define TNET_FINGERPRINT_MAX 256
+#endif /* TNET_FINGERPRINT_MAX */
+
+#if !defined(TNET_DTLS_MTU)
+# define TNET_DTLS_MTU 900
+#endif /* TNET_DTLS_MTU */
+
+typedef int tnet_fd_t;
+typedef uint16_t tnet_port_t;
+typedef int tnet_family_t;
+typedef char tnet_host_t[NI_MAXHOST];
+typedef char tnet_ip_t[INET6_ADDRSTRLEN];
+typedef uint8_t tnet_mac_address[6];
+typedef unsigned char tnet_fingerprint_t[TNET_FINGERPRINT_MAX + 1];
+
+typedef void tnet_transport_handle_t;
+
+typedef tsk_list_t tnet_interfaces_L_t; /**< List of @ref tnet_interface_t elements*/
+typedef tsk_list_t tnet_addresses_L_t; /**< List of @ref tnet_address_t elements*/
+
+typedef enum tnet_dtls_setup_e
+{
+ tnet_dtls_setup_none,
+ tnet_dtls_setup_actpass,
+ tnet_dtls_setup_active,
+ tnet_dtls_setup_passive,
+
+ TNET_DTLS_SETUP_MAX
+}
+tnet_dtls_setup_t;
+
+typedef enum tnet_proxy_type_e {
+ tnet_proxy_type_none = 0x00,
+ tnet_proxy_type_http = (0x01 << 0), // CONNECT using HTTP then starting SSL handshaking if needed
+ tnet_proxy_type_https = (0x01 << 1), // CONNECT using HTTPS then starting SSL handshaking if needed
+ tnet_proxy_type_socks4 = (0x01 << 2),
+ tnet_proxy_type_socks4a = (0x01 << 3),
+ tnet_proxy_type_socks5 = (0x01 << 4),
+}
+tnet_proxy_type_t;
+
+static const char* TNET_DTLS_SETUP_NAMES[TNET_DTLS_SETUP_MAX] =
+{
+ "UNKNOWN", "actpass", "active", "passive"
+};
+
+typedef enum tnet_dtls_hash_type_e
+{
+ tnet_dtls_hash_type_none,
+ tnet_dtls_hash_type_md5,
+ tnet_dtls_hash_type_sha1,
+ tnet_dtls_hash_type_sha256,
+ tnet_dtls_hash_type_sha512,
+
+ TNET_DTLS_HASH_TYPE_MAX
+}
+tnet_dtls_hash_type_t;
+
+// Hash names are case-insensitive but use lower case values because of https://bugzilla.mozilla.org/show_bug.cgi?id=828027
+static const char* TNET_DTLS_HASH_NAMES[TNET_DTLS_HASH_TYPE_MAX] =
+{
+ "UNKNOWN", "md5", "sha-1", "sha-256", "sha-512"
+};
+
+#if TNET_UNDER_WINDOWS
+# define TNET_INVALID_SOCKET INVALID_SOCKET
+# define TNET_ERROR_WOULDBLOCK WSAEWOULDBLOCK
+# define TNET_ERROR_INPROGRESS WSAEINPROGRESS
+# define TNET_ERROR_CONNRESET WSAECONNRESET
+# define TNET_ERROR_INTR WSAEINTR
+# define TNET_ERROR_ISCONN WSAEISCONN
+# define TNET_ERROR_EAGAIN TNET_ERROR_WOULDBLOCK /* WinSock FIX */
+# define TNET_ERROR_BROKENPIPE WSAECONNABORTED
+# if (TNET_UNDER_WINDOWS_RT || TNET_UNDER_WINDOWS_CE) /* gai_strerrorA() links against FormatMessageA which is not allowed on the store */
+# if !defined (WC_ERR_INVALID_CHARS)
+# define WC_ERR_INVALID_CHARS 0
+# endif
+ static TNET_INLINE const char* tnet_gai_strerror(int ecode)
+ {
+ static char aBuff[1024] = {0};
+
+ WCHAR *wBuff = gai_strerrorW(ecode);
+ int len;
+ if((len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wBuff, wcslen(wBuff), aBuff, sizeof(aBuff) - 1, NULL, NULL)) > 0)
+ {
+ aBuff[len] = '\0';
+ }
+ else
+ {
+ aBuff[0] = '\0';
+ }
+ return aBuff;
+ }
+# else
+# define tnet_gai_strerror gai_strerrorA
+# endif
+#else
+# define TNET_INVALID_SOCKET -1
+# define TNET_ERROR_WOULDBLOCK EWOULDBLOCK
+# define TNET_ERROR_INPROGRESS EINPROGRESS
+# define TNET_ERROR_CONNRESET ECONNRESET
+# define TNET_ERROR_INTR EINTR
+# define TNET_ERROR_ISCONN EISCONN
+# define TNET_ERROR_EAGAIN EAGAIN
+# define TNET_ERROR_BROKENPIPE EPIPE
+# define tnet_gai_strerror gai_strerror
+#endif
+#define TNET_INVALID_FD TNET_INVALID_SOCKET
+
+#ifdef _WIN32_WCE
+typedef TCHAR tnet_error_t[512];
+#else
+typedef char tnet_error_t[512];
+#endif
+
+TNET_END_DECLS
+
+#endif /* TNET_TYPES_H */
+
+
diff --git a/tinyNET/src/tnet_utils.c b/tinyNET/src/tnet_utils.c
new file mode 100644
index 0000000..64b1ea8
--- /dev/null
+++ b/tinyNET/src/tnet_utils.c
@@ -0,0 +1,2187 @@
+/*
+ * Copyright (C) 2010-2015 Mamadou DIOP.
+ *
+ * This file is part of Open Source Doubango Framework.
+ *
+ * DOUBANGO 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DOUBANGO 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 DOUBANGO.
+ *
+ */
+
+/**@file tnet_utils.c
+ * @brief Network utility functions.
+ *
+ */
+
+#include "tnet_utils.h"
+
+#include "tsk_thread.h"
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#include "tnet_socket.h"
+#include "tnet_endianness.h"
+#include "dns/tnet_dns_resolvconf.h"
+
+#include <string.h>
+
+#if TSK_UNDER_WINDOWS_RT
+#include <vector>
+extern std::vector<char> rt_tsk_str_to_native(Platform::String^ str);
+extern Platform::String^ rt_tsk_str_to_managed(char const* str);
+
+#endif /* TSK_UNDER_WINDOWS_RT */
+
+#if HAVE_NET_ROUTE_H
+# if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR // Header missing in device SDK but exist in simulator
+# include "net/_route.h" // from Doubango 3rd parties folder beacuse the one from iOS SDK is incomplete
+# else
+# include <net/route.h>
+# endif
+#endif /* HAVE_NET_ROUTE_H */
+
+#if HAVE_NET_IF_TYPES_H
+# include <net/if_types.h>
+#endif /* HAVE_NET_IF_TYPES_H */
+
+#if HAVE_NET_IF_DL_H
+# include <net/if_dl.h>
+#endif /* HAVE_NET_IF_DL_H */
+
+#if HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif /* HAVE_SYS_RESOURCE_H */
+
+#if HAVE_NETPACKET_PACKET_H
+# include <netpacket/packet.h>
+#endif /* HAVE_NETPACKET_PACKET_H */
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#endif /* HAVE_DIRENT_H */
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif /* HAVE_ARPA_INET_H */
+
+#ifndef AF_LINK
+# define AF_LINK AF_PACKET
+#endif /* AF_LINK */
+
+/**@defgroup tnet_utils_group Network utility functions.
+ */
+
+
+/**@ingroup tnet_utils_group
+ * Creates new @ref tnet_interface_t object.
+ */
+tnet_interface_t* tnet_interface_create(const char* description, const void* mac_address, tsk_size_t mac_address_length)
+{
+ return (tnet_interface_t*)tsk_object_new(tnet_interface_def_t, description, mac_address, mac_address_length);
+}
+
+/**@ingroup tnet_utils_group
+ * Creates new @ref tnet_address_t object.
+ */
+tnet_address_t* tnet_address_create(const char* ip)
+{
+ return (tnet_address_t*)tsk_object_new(tnet_address_def_t, ip);
+}
+
+/**@ingroup tnet_utils_group
+ *
+ * Gets last network error description.
+ *
+ * @param [out] error The short description of the last network error.
+ **/
+void tnet_getlasterror(tnet_error_t *error)
+{
+ int err = tnet_geterrno();
+ memset(*error, 0, sizeof(*error));
+
+#if TNET_UNDER_WINDOWS_RT
+ // FormatMessageA Not allowed on Market
+ static WCHAR wBuff[1024] = { 0 };
+ FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ tsk_null,
+ err,
+ 0,
+ wBuff,
+ sizeof(wBuff)-1,
+ tsk_null);
+ WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, wBuff, wcslen(wBuff), *error, sizeof(*error) - 1, NULL, NULL);
+#elif TNET_UNDER_WINDOWS
+ {
+#ifdef _WIN32_WCE
+ FormatMessage
+#else
+ FormatMessageA
+#endif
+ (
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ tsk_null,
+ err,
+ 0,
+ *error,
+ sizeof(*error) - 1,
+ tsk_null);
+ }
+#else
+ strerror_r(err, *error, sizeof(*error));
+ //sprintf(*error, "Network error (%d).", err);
+#endif
+}
+
+/**@ingroup tnet_utils_group
+ * Gets last error number. Will call @a WSAGetLastError() on Windows and
+ * errno on unix-like systems.
+ * @retval Error number.
+ */
+int tnet_geterrno()
+{
+#if TNET_UNDER_WINDOWS
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+
+/**@ingroup tnet_utils_group
+ * Gets the list of all network interfaces/adapters.
+ *
+ * @retval Network interfaces.
+ **/
+tnet_interfaces_L_t* tnet_get_interfaces()
+{
+ tnet_interfaces_L_t * ifaces = tsk_list_create();
+
+#if TNET_UNDER_WINDOWS/*=== WINDOWS XP/VISTA/7/CE===*/
+#if TNET_UNDER_WINDOWS_RT
+ TSK_DEBUG_ERROR("Not implemented on your OS");
+ goto bail;
+#else /* !TNET_UNDER_WINDOWS_RT */
+#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
+#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
+
+ PIP_ADAPTER_INFO pAdapterInfo = NULL;
+ PIP_ADAPTER_INFO pAdapter = NULL;
+ DWORD dwRetVal = 0;
+
+ ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
+ pAdapterInfo = (IP_ADAPTER_INFO *)MALLOC(sizeof(IP_ADAPTER_INFO));
+ if (pAdapterInfo == NULL)
+ {
+ TSK_DEBUG_ERROR("Error allocating memory needed to call GetAdaptersinfo.");
+ goto bail;
+ }
+ // Make an initial call to GetAdaptersInfo to get the necessary size into the ulOutBufLen variable
+ if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
+ {
+ FREE(pAdapterInfo);
+ pAdapterInfo = (IP_ADAPTER_INFO *)MALLOC(ulOutBufLen);
+ if (pAdapterInfo == NULL)
+ {
+ TSK_DEBUG_ERROR("Error allocating memory needed to call GetAdaptersinfo.");
+ goto bail;
+ }
+ }
+
+ if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR)
+ {
+ pAdapter = pAdapterInfo;
+ while (pAdapter)
+ {
+ tnet_interface_t *iface;
+
+ if (pAdapter->Type == MIB_IF_TYPE_LOOPBACK){
+ continue;
+ }
+
+ iface = tnet_interface_create(pAdapter->Description, pAdapter->Address, pAdapter->AddressLength);
+ iface->index = pAdapter->Index;
+ tsk_list_push_back_data(ifaces, &(iface));
+
+ pAdapter = pAdapter->Next;
+ }
+ }
+
+ if (pAdapterInfo)
+ {
+ FREE(pAdapterInfo);
+ }
+
+
+#undef MALLOC
+#undef FREE
+#endif /* !TNET_UNDER_WINDOWS_RT */
+
+#elif HAVE_IFADDRS_H && HAVE_GETIFADDRS /*=== Using getifaddrs ===*/
+
+ // see http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html
+ struct ifaddrs *ifaddr = tsk_null, *ifa = tsk_null;
+
+ /* Get interfaces */
+ if(getifaddrs(&ifaddr) == -1){
+ TSK_DEBUG_ERROR("getifaddrs failed and errno= [%d]", tnet_geterrno());
+ goto bail;
+ }
+
+ for(ifa = ifaddr; ifa; ifa = ifa->ifa_next){
+ if((ifa->ifa_flags & IFF_LOOPBACK) || !(ifa->ifa_flags & IFF_UP)) {
+ continue;
+ }
+
+ if(ifa->ifa_addr->sa_family != AF_LINK){
+ continue;
+ }
+
+#if defined(__linux__) && 0 /* FIXME */
+ {
+ struct ifreq ifr;
+ tnet_fd_t fd = TNET_INVALID_FD;
+
+ if((fd = socket(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP)) < 0){
+ TSK_DEBUG_ERROR("Failed to create new DGRAM socket and errno= [%d]", tnet_geterrno());
+ goto next;
+ }
+
+ ifr.ifr_addr.sa_family = ifa->ifa_addr->sa_family;
+ strcpy(ifr.ifr_name, ifa.ifa_name);
+ if(tnet_ioctl(fd, SIOCGIFHWADDR, &ifr)<0){
+ TSK_DEBUG_ERROR("tnet_ioctl(SIOCGIFHWADDR)", tnet_geterrno());
+ goto next;
+ }
+ else{
+ //sockaddr_dl* sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ tnet_interface_t *iface = tnet_interface_create(ifr->ifr_name, ifr->ifr_hwaddr.sa_data, 6);
+ tsk_list_push_back_data(ifaces, (void**)&(iface));
+ }
+ next:
+ tnet_sockfd_close(&fd);
+ }
+#else
+ {
+ //struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifa->ifa_addr;
+ tnet_interface_t *iface = tnet_interface_create(ifa->ifa_name, ifa->ifa_addr, 6);
+ iface->index = if_nametoindex(ifa->ifa_name);
+ tsk_list_push_back_data(ifaces, (void**)&(iface));
+ }
+#endif
+
+ }/* for */
+
+ freeifaddrs(ifaddr);
+
+#else /*=== ANDROID,... --> Using SIOCGIFCONF and SIOCGIFHWADDR ===*/
+
+ tnet_fd_t fd = TNET_INVALID_FD;
+ char buffer[1024];
+ struct ifconf ifc;
+
+ struct sockaddr_in *sin;
+ struct ifreq *ifr;
+
+ if((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
+ TSK_DEBUG_ERROR("Failed to create new DGRAM socket and errno= [%d]", tnet_geterrno());
+ goto done;
+ }
+
+ ifc.ifc_len = sizeof(buffer);
+ ifc.ifc_buf = buffer;
+
+ if(ioctl(fd, SIOCGIFCONF, &ifc) < 0){
+ TSK_DEBUG_ERROR("ioctl(SIOCGIFCONF) failed and errno= [%d]", tnet_geterrno());
+ goto done;
+ }
+ if(!ifr || !ifc.ifc_req){
+ TSK_DEBUG_ERROR("ifr or ifc.ifc_req is null");
+ goto done;
+ }
+
+ if(!ifr->ifr_name){
+ TSK_DEBUG_ERROR("ifr->ifr_name is null");
+ goto done;
+ }
+
+ for(ifr = ifc.ifc_req; ifr && !tsk_strempty(ifr->ifr_name); ifr++){
+ sin = (struct sockaddr_in *)&(ifr->ifr_addr);
+ // TODO: IPAddress if needed
+ if(/*ioctl(fd, SIOCGIFFLAGS, &ifr) == 0*/1){
+ if (!(ifr->ifr_flags & IFF_LOOPBACK) && (ifr->ifr_flags & IFF_UP)){
+ if(/*ioctl(fd, SIOCGIFHWADDR, &ifr) == 0*/1){
+ tnet_interface_t *iface = tnet_interface_create(ifr->ifr_name, ifr->ifr_hwaddr.sa_data, 6);
+ tsk_list_push_back_data(ifaces, (void**)&(iface));
+ //iface->index = if_nametoindex(ifr->ifr_name);
+ }
+ }
+ }
+ else
+ {
+ TSK_DEBUG_ERROR("ioctl(SIOCGIFFLAGS) failed and errno= [%d]", tnet_geterrno());
+ }
+ }
+
+done:
+ tnet_sockfd_close(&fd);
+
+
+#endif
+
+bail:
+ return ifaces;
+}
+
+/**@ingroup tnet_utils_group
+ * Get all IP addresses of the local machine.
+ * @param family The @a family of the addresses to return.
+ * @param unicast Indicates whether to return @a unicast addresses or not (1=yes and 0=no).
+ * @param anycast Indicates whether to return @a anycast addresses or not (1=yes and 0=no).
+ * @param multicast Indicates whether to return @a multicast addresses or not (1=yes and 0=no).
+ * @param dnsserver Indicates whether to include dns servers or not (1=yes and 0=no).
+ * @param if_index the index of the interface for which to to retrieve IP addresses.
+ * -1 mean all interfaces.
+ * @retval List of all addresses.
+ */
+tnet_addresses_L_t* tnet_get_addresses(tnet_family_t family, tsk_bool_t unicast, tsk_bool_t anycast, tsk_bool_t multicast, tsk_bool_t dnsserver, long if_index)
+{
+ tnet_addresses_L_t *addresses = tsk_list_create();
+
+#if TNET_UNDER_WINDOWS
+#if TNET_UNDER_WINDOWS_RT
+ TSK_DEBUG_ERROR("Not implemented on your OS");
+#else /* !TSK_UNDER_WINDOWS_RT */
+
+#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
+#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
+
+ /* Declare and initialize variables */
+ tnet_ip_t ip;
+ DWORD dwSize = 0;
+ DWORD dwRetVal = 0;
+
+ int i = 0;
+
+ // Set the flags to pass to GetAdaptersAddresses
+ ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
+
+ LPVOID lpMsgBuf = NULL;
+
+ PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+ ULONG outBufLen = 0;
+
+ PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+ PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
+ PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
+ PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
+ IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
+ IP_ADAPTER_PREFIX *pPrefix = NULL;
+
+
+ outBufLen = sizeof(IP_ADAPTER_ADDRESSES);
+ pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);
+
+ // Make an initial call to GetAdaptersAddresses to get the
+ // size needed into the outBufLen variable
+ if (GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW){
+ FREE(pAddresses);
+ pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);
+ }
+ else goto bail;
+
+ if (pAddresses == NULL){
+ TSK_DEBUG_ERROR("Memory allocation failed for IP_ADAPTER_ADDRESSES struct.");
+ goto bail;
+ }
+
+ dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
+
+ if (dwRetVal == NO_ERROR) {
+ pCurrAddresses = pAddresses;
+ while (pCurrAddresses){
+ if ((if_index != -1) && (pCurrAddresses->IfIndex != if_index && pCurrAddresses->Ipv6IfIndex != if_index)){
+ goto next;
+ }
+ if (pCurrAddresses->OperStatus != IfOperStatusUp){
+ goto next;
+ }
+
+ /* == UNICAST addresses == */
+ pUnicast = pCurrAddresses->FirstUnicastAddress;
+ while (unicast && pUnicast){
+ //memset(ip, '\0', sizeof(ip));
+ tnet_get_sockip(pUnicast->Address.lpSockaddr, &ip);
+ TSK_DEBUG_INFO("Found local IP address = AdapterName=%s Ip=%s", pCurrAddresses->AdapterName, ip);
+ {
+ tnet_address_t *address = tnet_address_create(ip);
+ address->family = pUnicast->Address.lpSockaddr->sa_family;
+ address->unicast = 1;
+ tsk_list_push_ascending_data(addresses, &address);
+ }
+
+ pUnicast = pUnicast->Next;
+ }
+
+ /* == ANYCAST addresses == */
+ pAnycast = pCurrAddresses->FirstAnycastAddress;
+ while (anycast && pAnycast){
+ //memset(ip, '\0', sizeof(ip));
+ tnet_get_sockip(pAnycast->Address.lpSockaddr, &ip);
+ {
+ tnet_address_t *address = tnet_address_create(ip);
+ address->family = pAnycast->Address.lpSockaddr->sa_family;
+ address->anycast = 1;
+ tsk_list_push_ascending_data(addresses, &address);
+ }
+
+ pAnycast = pAnycast->Next;
+ }
+
+ /* == MULTYCAST addresses == */
+ pMulticast = pCurrAddresses->FirstMulticastAddress;
+ while (multicast && pMulticast){
+ //memset(ip, '\0', sizeof(ip));
+ tnet_get_sockip(pMulticast->Address.lpSockaddr, &ip);
+ {
+ tnet_address_t *address = tnet_address_create(ip);
+ address->family = pMulticast->Address.lpSockaddr->sa_family;
+ address->multicast = 1;
+ tsk_list_push_ascending_data(addresses, &address);
+ }
+
+ pMulticast = pMulticast->Next;
+ }
+
+ /* == DNS servers == */
+ pDnServer = pCurrAddresses->FirstDnsServerAddress;
+ while (dnsserver && pDnServer){
+ //memset(ip, '\0', sizeof(ip));
+ if (!tnet_get_sockip(pDnServer->Address.lpSockaddr, &ip)){
+ tnet_address_t *address = tnet_address_create(ip);
+ address->family = pDnServer->Address.lpSockaddr->sa_family;
+ address->dnsserver = 1;
+ tsk_list_push_ascending_data(addresses, &address);
+ }
+
+ pDnServer = pDnServer->Next;
+ }
+ next:
+ pCurrAddresses = pCurrAddresses->Next;
+ }
+ }
+
+ if (pAddresses){
+ FREE(pAddresses);
+ }
+
+#undef MALLOC
+#undef FREE
+
+ bail :
+
+#endif /* !TSK_UNDER_WINDOWS_RT */
+
+#else /* !TSK_UNDER_WINDOWS (MAC OS X, UNIX, ANDROID ...) */
+
+ tnet_ip_t ip;
+#if HAVE_IFADDRS_H && HAVE_GETIFADDRS /*=== Using getifaddrs ===*/
+
+ // see http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html
+ struct ifaddrs *ifaddr = tsk_null, *ifa = tsk_null;
+ struct sockaddr *addr;
+
+ /* Get interfaces */
+ if(getifaddrs(&ifaddr) == -1){
+ TSK_DEBUG_ERROR("getifaddrs failed and errno= [%d]", tnet_geterrno());
+ goto bail;
+ }
+
+ /* == Unicast addresses == */
+ for(ifa = ifaddr; ifa; ifa = ifa->ifa_next){
+ if(!ifa->ifa_addr){
+ continue;
+ }
+ // Skip loopback
+ if ((ifa->ifa_flags & IFF_LOOPBACK) || !(ifa->ifa_flags & IFF_UP)) {
+ continue;
+ }
+
+ // Skip unwanted interface
+ if (if_index != -1 && if_nametoindex(ifa->ifa_name) != if_index) {
+ continue;
+ }
+
+ // Only deal with Unicast address
+ if (unicast) {
+ if (family == AF_INET && ifa->ifa_addr->sa_family != AF_INET) {
+ continue;
+ }
+ if (family == AF_INET6 && ifa->ifa_addr->sa_family != AF_INET6) {
+ continue;
+ }
+ if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6) {
+ continue;
+ }
+
+ // Get the IP string
+ addr = (struct sockaddr *) ifa->ifa_addr;
+ tnet_get_sockip(addr, &ip);
+
+ // Push a new address
+ tnet_address_t *address = tnet_address_create(ip);
+ address->family = ifa->ifa_addr->sa_family;
+ address->unicast = 1;
+ tsk_list_push_ascending_data(addresses, (void **) &address);
+ }
+ }
+
+ if (ifaddr) {
+ free(ifaddr);
+ }
+
+#else /* ANDROID or any system without getifaddrs */
+
+ tnet_address_t *address;
+ tnet_fd_t fd = TNET_INVALID_FD;
+ struct ifconf ifc;
+ struct ifreq *ifr = 0;
+ memset(&ifc, 0, sizeof(ifc));
+
+ if((fd = socket(family, SOCK_DGRAM, IPPROTO_UDP)) < 0){
+ TSK_DEBUG_ERROR("Failed to create new DGRAM socket and errno= [%d]", tnet_geterrno());
+ goto done;
+ }
+
+ if(ioctl(fd, SIOCGIFCONF, &ifc) < 0){
+ TSK_DEBUG_ERROR("ioctl(SIOCGIFCONF) failed and errno= [%d]", tnet_geterrno());
+ goto done;
+ }
+
+ if (!(ifr = (struct ifreq*) malloc(ifc.ifc_len))) {
+ TSK_DEBUG_ERROR("Could not malloc ifreq with size =%d", ifc.ifc_len);
+ goto done;
+ }
+
+ ifc.ifc_ifcu.ifcu_req = ifr;
+ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
+ TSK_DEBUG_ERROR("ioctl SIOCGIFCONF failed");
+ goto done;
+ }
+
+ int i;
+ for(i = 0; i < ifc.ifc_len / sizeof(struct ifreq); ++i){
+ if (unicast) {
+
+ }
+ // Skip unwanted interface
+ if (if_index != -1 && ifr->ifr_ifindex != if_index) {
+ continue;
+ }
+
+ // Get the IP string
+ if(tnet_get_sockip(&ifr[i].ifr_addr, &ip) == 0){
+ // Push a new address
+ if((address = tnet_address_create(ip))){
+ address->family = family;
+ address->unicast = unicast;
+ tsk_list_push_ascending_data(addresses, (void **) &address);
+ }
+ }
+ }
+
+done:
+ TSK_FREE(ifr);
+ tnet_sockfd_close(&fd);
+
+#endif /* HAVE_IFADDRS_H && HAVE_GETIFADDRS */
+
+bail:
+
+ /* == DNS servers == */
+ if(dnsserver){
+ TSK_DEBUG_INFO("Calling 'tnet_dns_resolvconf_parse()' to load DNS servers");
+ tnet_addresses_L_t * dns_servers;
+ if((dns_servers = tnet_dns_resolvconf_parse("/etc/resolv.conf"))){
+ tsk_list_pushback_list(addresses, dns_servers);
+ TSK_OBJECT_SAFE_FREE(dns_servers);
+ }
+ }
+
+#endif
+
+ return addresses;
+}
+
+
+/**@ingroup tnet_utils_group
+*/
+int tnet_get_mac_address(tnet_mac_address* address)
+{
+ static const tsk_size_t __tnet_mac_address_len = sizeof(tnet_mac_address) / sizeof(uint8_t/*tnet_mac_address[0]*/);
+ int ret = -1;
+ if (!address) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ }
+#if TNET_UNDER_WINDOWS
+# if TNET_UNDER_WINDOWS_RT
+ TSK_DEBUG_ERROR("Not implemented on your OS");
+# else /* !TSK_UNDER_WINDOWS_RT */
+ {
+ IP_ADAPTER_INFO *info = NULL, *pos;
+ DWORD size = 0;
+ ULONG _ret;
+
+ if ((_ret = GetAdaptersInfo(info, &size)) == ERROR_SUCCESS || _ret == ERROR_BUFFER_OVERFLOW) {
+ info = (IP_ADAPTER_INFO *)tsk_calloc(size + 1, 1);
+ if (info) {
+ if ((_ret = GetAdaptersInfo(info, &size)) == ERROR_SUCCESS) {
+ UINT i;
+ for (pos = info; pos != NULL && ret != 0; pos = pos->Next) {
+ if (pos->Type == MIB_IF_TYPE_LOOPBACK && pos->Next) { // skip loopback if we still have items to check
+ continue;
+ }
+ for (i = 0; i < pos->AddressLength && i < __tnet_mac_address_len; ++i) {
+ (*address)[i] = pos->Address[i];
+ }
+ ret = 0;
+ }
+ }
+ }
+ TSK_FREE(info);
+ }
+ }
+# endif /* TSK_UNDER_WINDOWS_RT */
+#elif HAVE_IFADDRS_H && HAVE_GETIFADDRS && HAVE_STRUCT_SOCKADDR_DL
+ struct ifaddrs *ifaddrs, *ifaddr;
+ struct sockaddr_dl* sdl;
+ if (getifaddrs(&ifaddrs) == 0) {
+ for (ifaddr = ifaddrs; ifaddr; ifaddr = ifaddr->ifa_next) {
+ // Skip loopback
+ if ((ifaddr->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+ sdl = (struct sockaddr_dl*)ifaddr->ifa_addr;
+ if (sdl->sdl_alen == __tnet_mac_address_len) {
+ memcpy(&(*address)[0], LLADDR(sdl), sdl->sdl_alen);
+ ret = 0;
+ break;
+ }
+ }
+ freeifaddrs(ifaddrs);
+ }
+ else {
+ TSK_DEBUG_ERROR("getifaddrs failed");
+ }
+#elif defined(SIOCGIFHWADDR)
+ struct ifreq ifr;
+ struct ifconf ifc;
+ char buf[1024];
+
+ tnet_fd_t fd = tnet_soccket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (fd == TNET_INVALID_FD) {
+ TSK_DEBUG_ERROR("Failed to create socket");
+ return -1;
+ }
+
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
+ TSK_DEBUG_ERROR("ioctl(%d, SIOCGIFCONF) failed", fd);
+ tnet_sockfd_close(&fd);
+ return -1;
+ }
+
+ struct ifreq* it = ifc.ifc_req;
+ const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
+
+ for (; it != end; ++it) {
+ strcpy(ifr.ifr_name, it->ifr_name);
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) {
+ if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // skip loopback
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
+ tsk_size_t min_size = TSK_MIN(__tnet_mac_address_len, 6);
+ memcpy(&(*address)[0], &ifr.ifr_hwaddr.sa_data[0], min_size);
+ ret = 0;
+ break;
+ }
+ }
+ }
+ else {
+ TSK_DEBUG_WARN("ioctl(%d, SIOCGIFFLAGS) failed", fd);
+ }
+ }
+#endif
+
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+* Retrieves the @a source IP address that has the best route to the specified IPv4 or IPv6 @a destination.
+* @param destination The destination address.
+* @param port The destination port.
+* @param type The socket type.
+* @param source The best @a source.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_getbestsource(const char* destination, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t *source)
+{
+ int ret = -1;
+ struct sockaddr_storage destAddr;
+
+#if TNET_UNDER_WINDOWS
+ long dwBestIfIndex = -1;
+#endif
+#if TNET_UNDER_WINDOWS_RT
+ Windows::Networking::Connectivity::ConnectionProfile^ profile;
+#endif
+
+ if (!destination || !source){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ goto bail;
+ }
+
+ memset(*source, '\0', sizeof(*source));
+
+ // special cases for Windows Phone device and emulator
+#if TNET_UNDER_WINDOWS_PHONE
+ if (tsk_strequals(destination, "127.0.0.1")){
+ memcpy(*source, "127.0.0.1", 9);
+ ret = 0; goto bail;
+ }
+ if(tsk_strequals(destination, "::1")){
+ memcpy(*source, "::1", 3);
+ ret = 0; goto bail;
+ }
+#endif
+
+ if((ret = tnet_sockaddr_init(destination, port, type, &destAddr))){
+ goto bail;
+ }
+
+#if TNET_UNDER_WINDOWS_RT /* Windows Phone 8, Surface or any RT */
+ profile = Windows::Networking::Connectivity::NetworkInformation::GetInternetConnectionProfile();
+
+ if (profile != nullptr && profile->NetworkAdapter != nullptr){
+ TSK_DEBUG_INFO("Network profile IanaInterfaceType = %d", profile->NetworkAdapter->IanaInterfaceType);
+ Windows::Foundation::Collections::IVectorView<Windows::Networking::HostName^>^ HostNames = Windows::Networking::Connectivity::NetworkInformation::GetHostNames();
+
+ if(HostNames->Size > 0)
+ {
+ Windows::Foundation::Collections::IIterator<Windows::Networking::HostName^>^ HostName = HostNames->First();
+ do
+ {
+ std::vector<char> CanonicalName = rt_tsk_str_to_native(HostName->Current->CanonicalName);
+ TSK_DEBUG_INFO("Checking IP address = %s", CanonicalName.data());
+ if((TNET_SOCKET_TYPE_IS_IPV4(type) && HostName->Current->IPInformation->PrefixLength->Value > 32) || (TNET_SOCKET_TYPE_IS_IPV6(type) && HostName->Current->IPInformation->PrefixLength->Value > 128))
+ {
+ TSK_DEBUG_INFO("Type mismatch - Skiping IP address=%s, IanaInterfaceType=%d, PrefixLength=%d", CanonicalName.data(), HostName->Current->IPInformation->NetworkAdapter->IanaInterfaceType, HostName->Current->IPInformation->PrefixLength->Value);
+ continue;
+ }
+
+
+ if(HostName->Current->IPInformation != nullptr)
+ {
+ // http://msdn.microsoft.com/en-us/library/windows/apps/windows.networking.connectivity.networkadapter.networkadapterid.aspx
+ // HostName->Current->IPInformation->NetworkAdapter->NetworkAdapterId not implemented on WP8
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+ tnet_socket_t* ss = tnet_socket_create(CanonicalName.data(), TNET_SOCKET_PORT_ANY, type);
+ if(ss)
+ {
+ ret = connect(ss->fd, (const sockaddr*)&destAddr, tnet_get_sockaddr_size((const sockaddr*)&destAddr));
+ if(ret && tnet_geterrno() == TNET_ERROR_EAGAIN)
+ {
+ ret = tnet_sockfd_waitUntilWritable(ss->fd, 500);
+ }
+ TSK_OBJECT_SAFE_FREE(ss);
+ }
+# else
+ if(HostName->Current->IPInformation->NetworkAdapter->IanaInterfaceType == profile->NetworkAdapter->IanaInterfaceType)
+ {
+ ret = 0;
+ }
+#endif /* */
+
+ if(ret == 0)
+ {
+ TSK_DEBUG_INFO("Using best IP address = %s :)", CanonicalName.data());
+ memcpy(*source, CanonicalName.data(), TSK_MIN(tsk_strlen(CanonicalName.data()), sizeof(*source)));
+ ret = 0;
+ goto bail;
+ }
+ TSK_DEBUG_INFO("Connection check - Skiping IP address = %s", CanonicalName.data());
+ }
+ }
+ while(HostName->MoveNext());
+ }
+ }
+ else
+ {
+ TSK_DEBUG_ERROR("No network connection available");
+ }
+
+#elif TNET_UNDER_WINDOWS /* Windows XP/Vista/7 and Windows Mobile */
+ if(GetBestInterfaceEx((struct sockaddr*)&destAddr, &dwBestIfIndex) != NO_ERROR){
+ ret = tnet_geterrno();
+ TNET_PRINT_LAST_ERROR("GetBestInterfaceEx() failed.");
+ goto bail;
+ }
+ else{
+ tnet_addresses_L_t* addresses = tsk_null;
+ const tsk_list_item_t* item;
+
+ if (!(addresses = tnet_get_addresses(TNET_SOCKET_TYPE_IS_IPV6(type) ? AF_INET6 : AF_INET, tsk_true, tsk_false, tsk_false, tsk_false, dwBestIfIndex))){
+ ret = -2;
+ TSK_DEBUG_ERROR("Failed to retrieve addresses.");
+ goto bail;
+ }
+
+ tsk_list_foreach(item, addresses){
+ const tnet_address_t* address = item->data;
+ if (address && address->ip){
+ memcpy(*source, address->ip, tsk_strlen(address->ip) > sizeof(*source) ? sizeof(*source) : tsk_strlen(address->ip));
+ ret = 0;
+ break; // First is good for us.
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(addresses);
+ }
+#elif HAVE_NET_ROUTE_H && HAVE_IFADDRS_H && HAVE_GETIFADDRS /* Mac OS X, iPhone, iPod Touch, iPad and Linux family except Android */
+ /* Thanks to Laurent Etiemble */
+
+ int sdl_index = -1;
+
+#if HAVE_STRUCT_RT_METRICS && HAVE_STRUCT_SOCKADDR_DL
+ static int seq = 1234;
+ char buf[1024];
+ char *cp;
+ int s, i, l, rlen;
+ int pid = getpid();
+ u_long rtm_inits;
+ struct rt_metrics rt_metrics;
+ struct sockaddr_dl *ifp = NULL;
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct sockaddr_dl so_ifp;
+#endif /* HAVE_STRUCT_RT_METRICS && HAVE_STRUCT_SOCKADDR_DL */
+
+ struct sockaddr_storage so_dst = destAddr;
+ struct sockaddr *sa = NULL;
+ struct ifaddrs *ifaddr = 0, *ifa = tsk_null;
+ tnet_ip_t ip;
+
+#if HAVE_STRUCT_RT_METRICS && HAVE_STRUCT_SOCKADDR_DL
+ bzero(rtm, 1024);
+ cp = (char *)(rtm + 1);
+
+ so_ifp.sdl_index = 0;
+ so_ifp.sdl_family = AF_LINK;
+ so_ifp.sdl_len = sizeof(struct sockaddr_dl);
+
+ rtm->rtm_type = RTM_GET;
+ rtm->rtm_flags = RTF_STATIC | RTF_UP | RTF_GATEWAY;
+ rtm->rtm_version = RTM_VERSION;
+ rtm->rtm_seq = ++seq;
+ rtm->rtm_addrs = RTA_DST | RTA_IFP;
+ rtm->rtm_rmx = rt_metrics;
+ rtm->rtm_inits = rtm_inits;
+ rtm->rtm_index = 0;
+
+ /** Roundup value to a 4 bytes boundary. */
+#define ROUNDUP(a) \
+((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+
+ l = ROUNDUP(so_dst.ss_len);
+ memcpy(&so_dst, cp, l);
+ cp += l;
+
+ l = ROUNDUP(so_ifp.sdl_len);
+ memcpy(&so_ifp, cp, l);
+ cp += l;
+
+ l = cp - buf;
+ rtm->rtm_msglen = l;
+
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ // TODO
+ }
+
+ if ((rlen = write(s, rtm, l)) < 0) {
+ TSK_DEBUG_INFO("writing to routing socket");
+ // TODO
+ }
+ do {
+ l = read(s, rtm, 1024);
+ } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
+
+ /** Advance an address to the closest 4 bytes boundary. */
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+ if (rtm->rtm_errno == 0 && rtm->rtm_addrs) {
+ cp = (char *)(rtm + 1);
+ for (i = 1; i; i <<= 1) {
+ if (i & rtm->rtm_addrs) {
+ sa = (struct sockaddr *)cp;
+ switch (i) {
+ case RTA_IFP:
+ ifp = (struct sockaddr_dl *) sa;
+ break;
+ }
+ ADVANCE(cp, sa);
+ }
+ }
+ }
+ if(ifp){
+ sdl_index = ifp->sdl_index;
+ }
+#endif /* HAVE_STRUCT_RT_METRICS && HAVE_STRUCT_SOCKADDR_DL */
+
+ /* Get interfaces */
+ if(getifaddrs(&ifaddr) == -1){
+ TNET_PRINT_LAST_ERROR("getifaddrs() failed.");
+ goto bail;
+ }
+
+ for(ifa = ifaddr; ifa; ifa = ifa->ifa_next){
+ if ((ifa->ifa_flags & IFF_LOOPBACK) || !(ifa->ifa_flags & IFF_UP)) {
+ continue;
+ }
+
+ if (sdl_index != -1 && if_nametoindex(ifa->ifa_name) != sdl_index) {
+ continue;
+ }
+
+ if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != destAddr.ss_family) {
+ continue;
+ }
+
+ if (destAddr.ss_family == AF_INET6) {
+ if (IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr) ^
+ IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) &destAddr)->sin6_addr)) {
+ continue;
+ }
+ if (IN6_IS_ADDR_SITELOCAL(&((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr) ^
+ IN6_IS_ADDR_SITELOCAL(&((struct sockaddr_in6 *) &destAddr)->sin6_addr)) {
+ continue;
+ }
+ }
+
+ tnet_get_sockip((struct sockaddr *) ifa->ifa_addr, &ip);
+
+ memcpy(*source, ip, tsk_strlen(ip) > sizeof(*source) ? sizeof(*source) : tsk_strlen(ip));
+ ret = 0;
+ goto bail; // First is good for us.
+ }
+
+
+#else /* All other systems (Google Android, Unix-Like systems, uLinux, ....) */
+ TSK_DEBUG_WARN("getbestroute() not supported on this OS");
+ memcpy(*source,
+ TNET_SOCKET_TYPE_IS_IPV6(type) ? "::" : "0.0.0.0",
+ TNET_SOCKET_TYPE_IS_IPV6(type) ? 2 : 7
+ );
+#endif
+
+bail:
+ return ret;
+}
+
+
+/**@ingroup tnet_utils_group
+ *
+ * Converts human-readable text strings representing hostnames or IP addresses into a dynamically allocated linked list of struct addrinfo structures.
+ * You MUST call @ref tnet_freeaddrinfo() function to free the result.
+ *
+ * @param [in] node A pointer to a NULL-terminated ANSI string that contains a host (node) name or a numeric host address string. For the Internet protocol, the numeric host address string is a dotted-decimal IPv4 address or an IPv6 hex address..
+ * @param [in] service A pointer to a NULL-terminated ANSI string that contains either a service name or port number represented as a string.
+ * @param [in] hints A pointer to an addrinfo structure that provides hints about the type of socket the caller supports.
+ * @param [out] res A pointer to a linked list of one or more addrinfo structures that contains response information about the host.
+ *
+ * @retval Success returns zero. Failure returns a nonzero error code.
+ **/
+int tnet_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
+{
+ int ret = -1;
+ if (hints && (ret = getaddrinfo(node, service, hints, res))){
+ TSK_DEBUG_ERROR("getaddrinfo(family=%d, node=%s and service=%s) failed: [%s]", hints->ai_family, node, service, tnet_gai_strerror(ret));
+ }
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+ *
+ * This function frees address information previously allocated using @ref tnet_getaddrinfo.
+ *
+ * @param [in] ai The address information to free.
+ **/
+void tnet_freeaddrinfo(struct addrinfo *ai)
+{
+ if (ai){
+ freeaddrinfo(ai);
+ }
+}
+
+/**@ingroup tnet_utils_group
+ * Converts a descriptor to @b sockaddr_storage structure.
+ * @param fd The descriptor to convert.
+ * @param result @b sockaddr_storage structre representing the desciptor.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_getsockname(tnet_fd_t fd, struct sockaddr_storage *result)
+{
+ if (fd > 0 && result){
+ socklen_t namelen = sizeof(*result);
+ return getsockname(fd, (struct sockaddr*)result, &namelen);
+ }
+ return -1;
+}
+
+int tnet_getpeername(tnet_fd_t fd, struct sockaddr_storage *result)
+{
+ if (fd > 0 && result){
+ socklen_t namelen = sizeof(*result);
+ return getpeername(fd, (struct sockaddr*)result, &namelen);
+ }
+ return -1;
+}
+
+/**@ingroup tnet_utils_group
+ * Retrieves the socket type of a File Descriptor.
+ * @param fd The File descriptor for which to retrive the type.
+ * @retval @ref tnet_socket_type_t.
+ */
+tnet_socket_type_t tnet_get_socket_type(tnet_fd_t fd)
+{
+ tnet_socket_type_t type = tnet_socket_type_invalid;
+
+ /*if(fd >0)
+ {
+ struct sockaddr_storage ss;
+ if(!tnet_get_sockaddr(fd, &ss))
+ {
+ if(((struct sockaddr *)&ss)->sa_family == AF_INET)
+ {
+ TNET_SOCKET_TYPE_AS_IPV4(type);
+ }
+ else if(((struct sockaddr *)&ss)->sa_family == AF_INET6)
+ {
+ TNET_SOCKET_TYPE_AS_IPV6(type);
+ }
+ }
+ }*/
+
+ return type;
+}
+
+/**@ingroup tnet_utils_group
+ * Gets the IP family of the @a host (e.g. "google.com" or "192.168.16.104" or "::1").
+ * If the @a host is FQDN associated with both IPv4 and IPv6 then the result is unpredictable.
+ * @param host The IP address or hostname for which to get the IP family.
+ * @param port The port associated to the @a host. Will be used as the default service.
+ * @retval @a AF_* if succeed and @a AF_UNSPEC otherwise.
+ */
+tnet_family_t tnet_get_family(const char* host, tnet_port_t port)
+{
+ tnet_family_t ret = AF_UNSPEC;
+ if (host){
+ int status;
+ tsk_istr_t srv;
+ struct addrinfo *result = tsk_null;
+ struct addrinfo hints;
+
+ /* set the port: used as the default service */
+ if (port){
+ tsk_itoa(port, &srv);
+ }
+ else{
+ memset(srv, '\0', sizeof(srv));
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+
+ if ((status = tnet_getaddrinfo(host, srv, &hints, &result))) {
+ TNET_PRINT_LAST_ERROR("getaddrinfo(%s:%d) failed", host, port);
+ goto done;
+ }
+
+ /* Get the First result. */
+ if (result) {
+ ret = result->ai_family;
+ goto done;
+ }
+ done:
+ tnet_freeaddrinfo(result);
+ }
+
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+ * Gets the IP address and the Port of a @b sockaddr object.
+ * @param addr [in] A pointer to @b sockaddr structure for which to retrieve the IP address and port.
+ * @param ip [out] The IP address.
+ * @param port [out] The port.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_get_sockip_n_port(const struct sockaddr *addr, tnet_ip_t *ip, tnet_port_t *port)
+{
+ int status = -1;
+
+ if (addr->sa_family == AF_INET){
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)addr;
+ if (port){
+ *port = tnet_ntohs(sin->sin_port);
+ status = 0;
+ }
+ if (ip){
+ if ((status = tnet_getnameinfo((const struct sockaddr*)sin, sizeof(*sin), *ip, sizeof(*ip), 0, 0, NI_NUMERICHOST))){
+ return status;
+ }
+ }
+ }
+ else if (addr->sa_family == AF_INET6)
+ {
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)addr;
+#if TNET_UNDER_WINDOWS
+ int index;
+#endif
+ if (port){
+ *port = tnet_ntohs(sin6->sin6_port);
+ status = 0;
+ }
+ if (ip){
+ if ((status = tnet_getnameinfo((const struct sockaddr*)sin6, sizeof(*sin6), *ip, sizeof(*ip), 0, 0, NI_NUMERICHOST))){
+ return status;
+ }
+
+#if TNET_UNDER_WINDOWS
+ if ((index = tsk_strindexOf(*ip, tsk_strlen(*ip), "%")) > 0){
+ *(*ip + index) = '\0';
+ }
+#endif
+ }
+ }
+ else
+ {
+ TSK_DEBUG_ERROR("Unsupported address family.");
+ return status;
+ }
+
+ return status;
+}
+
+/**@ingroup tnet_utils_group
+ * Gets the IP address and port of the remote peer.
+ * <b>The socket MUST be connect()ed.</b>
+ * @param localFD Local socket.
+ * @param ip [out] The IP address of the remote peer.
+ * @param port [out] The remote (peer) port.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_get_peerip_n_port(tnet_fd_t localFD, tnet_ip_t *ip, tnet_port_t *port)
+{
+ if (port){
+ *port = 0;
+ }
+
+ if (localFD > 0){
+ int status;
+ socklen_t len;
+ struct sockaddr_storage ss;
+
+ len = sizeof(ss);
+ if ((status = getpeername(localFD, (struct sockaddr *)&ss, &len))){
+ TSK_DEBUG_ERROR("TNET_GET_SOCKADDR has failed with status code: %d", status);
+ return -1;
+ }
+
+ return tnet_get_sockip_n_port(((struct sockaddr *)&ss), ip, port);
+ }
+
+ TSK_DEBUG_ERROR("Could not use an invalid socket description.");
+ return -1;
+}
+
+/**@ingroup tnet_utils_group
+ * Gets the IP address and the Port of a socket (File descriptor).
+ * @param fd The decriptor for which to retrive the IP address and port.
+ * @param getlocal Whether to get local or remote ip and port
+ * @param ip [out] The IP address of the local socket.
+ * @param port [out] The port of the local socket.
+
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_get_ip_n_port(tnet_fd_t fd, tsk_bool_t getlocal, tnet_ip_t *ip, tnet_port_t *port)
+{
+ if (port){
+ *port = 0;
+ }
+
+ if (fd > 0){
+ int status;
+ struct sockaddr_storage ss;
+ status = getlocal ? tnet_getsockname(fd, &ss) : tnet_getpeername(fd, &ss);
+ if (status){
+ TNET_PRINT_LAST_ERROR("TNET_GET_SOCKADDR has failed with status code: %d", status);
+ return -1;
+ }
+
+ return tnet_get_sockip_n_port(((struct sockaddr *)&ss), ip, port);
+ }
+
+ TSK_DEBUG_ERROR("Could not use an invalid socket description.");
+ return -1;
+}
+
+/**@ingroup tnet_utils_group
+ * Gets the maximum number of file descriptors (FDs) this process is allowed to open.
+ */
+int tnet_get_fd_max_allowed(tsk_size_t* fd_size)
+{
+#if HAVE_GETRLIMIT
+ struct rlimit rl;
+ int ret;
+ if (!fd_size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ ret = getrlimit(RLIMIT_NOFILE, &rl);
+ if (ret) {
+ TSK_DEBUG_ERROR("getrlimit(RLIMIT_NOFILE) failed with error code = %d", tnet_geterrno());
+ return ret;
+ }
+ *fd_size = rl.rlim_cur;
+ return 0;
+#elif HAVE_GETDTABLESIZE
+ return getdtablesize();
+#else
+ return -1;
+#endif
+}
+
+/**@ingroup tnet_utils_group
+ * Sets the maximum number of file descriptors (FDs) this process is allowed to open.
+ */
+int tnet_set_fd_max_allowed(tsk_size_t fd_size)
+{
+#if HAVE_SETRLIMIT && HAVE_GETRLIMIT
+ struct rlimit rl;
+ int ret;
+ ret = getrlimit(RLIMIT_NOFILE, &rl);
+ if (!ret) {
+ rl.rlim_cur = fd_size;
+ ret = setrlimit(RLIMIT_NOFILE, &rl);
+ }
+ return ret;
+#else
+ return -1;
+#endif
+}
+
+/**@ingroup tnet_utils_group
+ * Gets the number of FDs opened by this process.
+ */
+int tnet_get_fd_opened_count(tsk_size_t* count)
+{
+#if HAVE_OPENDIR && HAVE_CLOSEDIR && HAVE_GETPID && HAVE_STRUCT_DIRENT
+ int fd_count;
+ char buf[1024];
+ struct dirent *dp;
+ DIR *dir;
+
+ if (!count) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *count = 0;
+ snprintf(buf, 1024, "/proc/%i/fd/", getpid());
+ dir = opendir(buf);
+ while ((dp = readdir(dir))) {
+ (*count)++;
+ }
+ closedir(dir);
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+/**@ingroup tnet_utils_group
+ * Provides protocol-independent name resolution from an address to an ANSI host name and from a port number to the ANSI service name.
+ * @param sa A pointer to a socket address structure that contains the address and port number of the socket. For IPv4, the sa parameter points to a sockaddr_in structure. For IPv6, the sa parameter points to a @b sockaddr_in6 structure.
+ * @param salen The length, in bytes, of the structure pointed to by the sa parameter.
+ * @param node A pointer to an ANSI string used to hold the host name. On success, a pointer to the host name is returned as a Fully Qualified Domain Name (FQDN) by default. If the host parameter is NULL, this indicates the caller does not want to receive a host name string.
+ * @param nodelen The length, in bytes, of the buffer pointed to by the host parameter. The caller must provide a buffer large enough to hold the host name, including the terminating NULL character.
+ * @param service A pointer to an ANSI string to hold the service name. On success, a pointer is returned to an ANSI string that represents the service name associated with the port number. If the serv parameter is NULL, this indicates the caller does not want to receive a service name string.
+ * @param servicelen The length, in bytes, of the buffer pointed to by the serv parameter. The caller must provide a buffer large enough to hold the service name, including the terminating NULL character.
+ * @param flags A value used to customize processing of the @b getnameinfo function. See the Remarks section.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_getnameinfo(const struct sockaddr *sa, socklen_t salen, char* node, socklen_t nodelen, char* service, socklen_t servicelen, int flags)
+{
+ return getnameinfo(sa, salen, node, nodelen, service, servicelen, flags);
+}
+
+/**@ingroup tnet_utils_group
+ * Retrieves the standard host name for the local computer.
+ * @param result A pointer to a buffer that receives the local host name.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_gethostname(tnet_host_t* result)
+{
+ return gethostname(*result, sizeof(*result));
+}
+
+/**@ingroup tnet_utils_group
+ * see http://man7.org/linux/man-pages/man3/inet_pton.3.html
+ * @retval 1 if succeed.
+ */
+int tnet_inet_pton(int af, const char* src, void* dst)
+{
+ if (!src || !dst) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+#if HAVE_INET_PTON || TNET_UNDER_APPLE
+ return inet_pton(af, src, dst);
+#elif TNET_UNDER_WINDOWS && !(TNET_UNDER_WINDOWS_RT || TNET_UNDER_WINDOWS_CE)
+# if (_WIN32_WINNT <= 0x0501)
+ {
+ struct sockaddr_storage addr = { 0 };
+ int addr_len = (af == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
+ if (WSAStringToAddressA((LPSTR)src, af, NULL, (struct sockaddr *)&addr, &addr_len) == 0) {
+ if (af == AF_INET6) {
+ memcpy(dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16);
+ }
+ else {
+ memcpy(dst, &((struct sockaddr_in *)&addr)->sin_addr, 4);
+ }
+ return 1;
+ }
+ TNET_PRINT_LAST_ERROR("WSAStringToAddressA failed");
+ return -2;
+ }
+# else
+ return InetPtonA(af, src, dst);
+# endif // TNET_UNDER_WINDOWS
+#else
+ {
+ struct sockaddr_storage addr = { 0 };
+ int ret;
+ if ((ret = tnet_sockaddr_init(src, 0, (af == AF_INET6 ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4), &addr))) {
+ return -2;
+ }
+ if (af == AF_INET6) {
+ *((struct in6_addr *)dst) = ((struct sockaddr_in6 *)&addr)->sin6_addr;
+ }
+ else {
+ *((struct in_addr *)dst) = ((struct sockaddr_in *)&addr)->sin_addr;
+ }
+ return 1;
+ }
+#endif
+}
+
+/**@ingroup tnet_utils_group
+ * see http://pubs.opengroup.org/onlinepubs/009695399/functions/inet_ntop.html
+ */
+const char *tnet_inet_ntop(int af, const void *src, char *dst, int size)
+{
+ if (!src || !dst || size <= 0) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+ memset(dst, 0, size);
+#if HAVE_INET_NTOP || TNET_UNDER_APPLE
+ return inet_ntop(af, src, dst, size);
+#elif TNET_UNDER_WINDOWS && !(TNET_UNDER_WINDOWS_RT || TNET_UNDER_WINDOWS_CE)
+# if (_WIN32_WINNT <= 0x0501)
+ {
+ struct sockaddr_storage addr = { 0 };
+ int addr_len = sizeof(addr);
+ if (af == AF_INET6) {
+ if (size < INET6_ADDRSTRLEN) {
+ TSK_DEBUG_ERROR("Destination size too short(%d)", size);
+ return tsk_null;
+ }
+ ((struct sockaddr_in6 *)&addr)->sin6_family = AF_INET6;
+ memcpy(&((struct sockaddr_in6 *)&addr)->sin6_addr, src, 16);
+ }
+ else {
+ if (size < INET_ADDRSTRLEN) {
+ TSK_DEBUG_ERROR("Destination size too short(%d)", size);
+ return tsk_null;
+ }
+ ((struct sockaddr_in *)&addr)->sin_family = AF_INET;
+ memcpy(&((struct sockaddr_in *)&addr)->sin_addr, src, 4);
+ }
+ if (WSAAddressToStringA((struct sockaddr*)&addr, addr_len, NULL, dst, &size) == 0) {
+ return dst;
+ }
+ TNET_PRINT_LAST_ERROR("WSAAddressToStringA failed");
+ return tsk_null;
+ }
+# else
+ return InetNtopA(af, (PVOID)src, dst, size);
+# endif // TNET_UNDER_WINDOWS
+#else
+ {
+ struct sockaddr_storage addr = { 0 };
+ tnet_ip_t ip;
+ if (af == AF_INET6) {
+ if (size < INET6_ADDRSTRLEN) {
+ TSK_DEBUG_ERROR("Destination size too short(%d)", size);
+ return tsk_null;
+ }
+ addr.ss_family = AF_INET6;
+ ((struct sockaddr_in6 *)&addr)->sin6_addr = *((struct in6_addr *)src);
+
+ if (tnet_get_sockip((const struct sockaddr *)&addr, &ip)) {
+ return tsk_null;
+ }
+ memcpy(dst, ip, INET6_ADDRSTRLEN);
+ return dst;
+ }
+ else {
+ if (size < INET_ADDRSTRLEN) {
+ TSK_DEBUG_ERROR("Destination size too short(%d)", size);
+ return tsk_null;
+ }
+ addr.ss_family = AF_INET;
+ ((struct sockaddr_in *)&addr)->sin_addr = *((struct in_addr *)src);
+ if (tnet_get_sockip((const struct sockaddr *)&addr, &ip)) {
+ return tsk_null;
+ }
+ memcpy(dst, ip, INET_ADDRSTRLEN);
+ return dst;
+ }
+ }
+#endif
+}
+
+/**@ingroup tnet_utils_group
+ * Waits until the socket becomes writable/readable or @a timeout milliseconds passed.
+ * This function could be used just after you have @a connect()ed a non-blocking socket.
+ * @param fd The socket for which to check writability/readability.
+ * @param timeout The number of milliseconds to wait. The function will immediately return if the socket
+ * is already connected and writable/readable. Set the @a timeout value to -1 to wait indefinitely.
+ * @param writable Indicates whether to wait for writability or readability.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_sockfd_waitUntil(tnet_fd_t fd, long timeout, tsk_bool_t writable)
+{
+ int ret = -1;
+ fd_set fds;
+ struct timeval timetowait;
+
+ if (fd <= 0){
+ goto bail;
+ }
+
+ if (timeout >= 0){
+ timetowait.tv_sec = (timeout / 1000);
+ timetowait.tv_usec = (timeout % 1000) * 1000;
+ }
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ ret = select(fd + 1, writable ? 0 : &fds, writable ? &fds : 0, 0, (timeout >= 0) ? &timetowait : 0);
+
+ if (ret == 0){ /* timedout */
+ ret = -2;
+ }
+ else if (ret == 1/* the total number of socket handles that are ready */){
+ ret = 0; // Ok
+ }
+ //else: error
+
+bail:
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+ * NOT IMPLEMENTED.
+ */
+int tnet_sockfd_joingroup6(tnet_fd_t fd, const char* multiaddr, unsigned iface_index)
+{
+ int ret = -1;
+ //struct ipv6_mreq mreq6;
+ //struct sockaddr_storage ss;
+
+ //if((ret = tnet_sockaddr_init(multiaddr, 0, tnet_socket_type_udp_ipv6, &ss)))
+ //{
+ // return ret;
+ //}
+
+ //memcpy(&mreq6.ipv6mr_multiaddr, &((struct sockaddr_in6 *) &ss)->sin6_addr, sizeof(struct in6_addr));
+ //mreq6.ipv6mr_interface = iface_index;
+
+ //if((ret = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char*)&mreq6, sizeof(mreq6))))
+ //{
+ // TNET_PRINT_LAST_ERROR("Failed to join IPv6 multicast group.");
+ // return ret;
+ //}
+
+ return ret;
+}
+/**@ingroup tnet_utils_group
+ * NOT IMPLEMENTED.
+ */
+int tnet_sockfd_leavegroup6(tnet_fd_t fd, const char* multiaddr, unsigned iface_index)
+{
+ //if(multiaddr)
+ {
+ }
+ return -1;
+}
+
+/**@ingroup tnet_utils_group
+ * Performs DNS A/AAAA to convert the FQDN to IP address.
+ */
+int tnet_resolve(const char *fqdn, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t* out_ip, tnet_port_t* out_port)
+{
+ struct sockaddr_storage addr;
+ int ret = tnet_sockaddr_init(fqdn, port, type, &addr);
+ if (ret == 0){
+ return tnet_get_sockip_n_port((const struct sockaddr *)&addr, out_ip, out_port);
+ }
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+ * Converts human-readable text strings representing hostnames or IP addresses into a dynamically allocated linked list of struct addrinfo structures.
+ */
+int tnet_sockaddrinfo_init(const char *host, tnet_port_t port, enum tnet_socket_type_e type, struct sockaddr_storage *ai_addr, int *ai_family, int *ai_socktype, int *ai_protocol)
+{
+ int status = 0;
+ struct addrinfo *result = 0;
+ struct addrinfo *ptr = 0;
+ struct addrinfo hints;
+ tsk_istr_t p;
+
+ tsk_itoa(port, &p);
+
+ /* hints address info structure */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(type) ? AF_INET6 : AF_INET);
+ hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(type) ? SOCK_STREAM : SOCK_DGRAM;
+ hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(type) ? IPPROTO_TCP : IPPROTO_UDP;
+ hints.ai_flags = AI_PASSIVE;
+
+ /* Performs getaddrinfo */
+ if ((status = tnet_getaddrinfo(host, p, &hints, &result))){
+ TNET_PRINT_LAST_ERROR("getaddrinfo have failed.");
+ goto bail;
+ }
+
+ /* Find our address. */
+ for (ptr = result; ptr; ptr = ptr->ai_next){
+ /* Only IPv4 and IPv6 are supported */
+ if (ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){
+ continue;
+ }
+ /* duplicate addrinfo ==> Bad idea
+ *ai = tsk_calloc(1, sizeof (struct addrinfo));
+ memcpy (*ai, ptr, sizeof (struct addrinfo));
+ (*ai)->ai_addr = tsk_calloc(1, ptr->ai_addrlen);
+ memcpy((*ai)->ai_addr, ptr->ai_addr, ptr->ai_addrlen);
+ (*ai)->ai_addrlen = ptr->ai_addrlen;
+ (*ai)->ai_next = 0;
+ (*ai)->ai_canonname = 0;*/
+
+ if (ai_addr)memcpy(ai_addr, ptr->ai_addr, ptr->ai_addrlen);
+ if (ai_family) *ai_family = ptr->ai_family;
+ if (ai_socktype) *ai_socktype = ptr->ai_socktype;
+ if (ai_protocol) *ai_protocol = ptr->ai_protocol;
+
+ /* We prefer IPv4 but IPv6 can also work */
+ if (ptr->ai_family == AF_INET){
+ break;
+ }
+ }
+
+bail:
+ tnet_freeaddrinfo(result);
+
+ return status;
+}
+
+/**@ingroup tnet_utils_group
+ * Converts human-readable text strings representing hostnames or IP addresses into a @b sockaddr_storage structure.
+ * @param host The hostname/IP address to convert.
+ * @param port The local port associated to the host.
+ * @param type The type of the socket to create.
+ * @param addr [out] @b sockaddr_storage structure representing the @a host:port address.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_sockaddr_init(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *addr)
+{
+ int status;
+ struct sockaddr_storage ai_addr;
+
+ if ((status = tnet_sockaddrinfo_init(host, port, type, &ai_addr, 0, 0, 0))){
+ return status;
+ }
+
+ memcpy(addr, &ai_addr, sizeof(ai_addr));
+
+ return status;
+}
+
+/**@ingroup tnet_utils_group
+ * Converts human-readable text strings representing hostnames or IP addresses as socket (File descriptor).
+ * @param host The hostname/IP address to convert.
+ * @param port The local port associated to the host.
+ * @param type The type of the socket to create.
+ * @param fd [out] The socket representing the @a host:port address.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_sockfd_init(const char *host, tnet_port_t port, enum tnet_socket_type_e type, tnet_fd_t *fd)
+{
+ int status = -1;
+ struct sockaddr_storage ai_addr;
+ int ai_family, ai_socktype, ai_protocol;
+ *fd = TNET_INVALID_SOCKET;
+
+ if ((status = tnet_sockaddrinfo_init(host, port, type, &ai_addr, &ai_family, &ai_socktype, &ai_protocol))){
+ goto bail;
+ }
+
+ if ((*fd = (tnet_fd_t)socket(ai_family, ai_socktype, ai_protocol)) == TNET_INVALID_SOCKET){
+ TNET_PRINT_LAST_ERROR("Failed to create new socket.");
+ goto bail;
+ }
+
+#if TNET_USE_POLL || USE_POLL /* For win32 WSA* function the socket is auto. set to nonblocking mode. */
+ if ((status = tnet_sockfd_set_nonblocking(*fd))){
+ goto bail;
+ }
+#endif
+
+#if TNET_HAVE_SS_LEN
+ if((status = bind(*fd, (const struct sockaddr*)&ai_addr, ai_addr.ss_len)))
+#else
+ if ((status = bind(*fd, (const struct sockaddr*)&ai_addr, sizeof(ai_addr))))
+#endif
+ {
+ TNET_PRINT_LAST_ERROR("bind have failed.");
+ tnet_sockfd_close(fd);
+
+ goto bail;
+ }
+
+bail:
+ return (*fd == TNET_INVALID_SOCKET) ? status : 0;
+}
+
+/**@ingroup tnet_utils_group
+ * Changes the blocking mode of the socket.
+ * @param fd The socket for which to change to mode.
+ * @param nonBlocking The new mode (0 =blocking and 1=non-blocking).
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_sockfd_set_mode(tnet_fd_t fd, int nonBlocking)
+{
+ if (fd != TNET_INVALID_FD)
+ {
+#if TNET_UNDER_WINDOWS
+ ULONG mode = nonBlocking;
+ if (ioctlsocket(fd, FIONBIO, &mode))
+ //if(WSAIoctl(fd, FIONBIO, &nonblocking, sizeof(nonblocking), NULL, 0, NULL, NULL, NULL) == SOCKET_ERROR)
+ {
+ TNET_PRINT_LAST_ERROR("ioctlsocket(FIONBIO) have failed.");
+ return -1;
+ }
+#else
+ int flags;
+ if ((flags = fcntl(fd, F_GETFL, 0)) < 0) {
+ TNET_PRINT_LAST_ERROR("fcntl(F_GETFL) have failed.");
+ return -1;
+ }
+ if(fcntl(fd, F_SETFL, flags | (nonBlocking ? O_NONBLOCK : ~O_NONBLOCK)) < 0){
+ TNET_PRINT_LAST_ERROR("fcntl(O_NONBLOCK/O_NONBLOCK) have failed.");
+ return -1;
+ }
+#endif
+
+ // int on = 1;
+ // ioctl(fd, FIONBIO, (char *)&on);
+
+ }
+ return 0;
+}
+
+/**@ingroup tnet_utils_group
+ */
+int tnet_sockfd_reuseaddr(tnet_fd_t fd, int reuseAddr)
+{
+ if (fd != TNET_INVALID_FD) {
+ int ret;
+#if defined(SOLARIS)
+ static const char yes = '1';
+ static const char no = '0';
+#else
+ static const int yes = 1;
+ static const int no = 0;
+#endif
+ if ((ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)(reuseAddr ? &yes : &no), sizeof(int)))) {
+ TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEADDR, fd=%d) have failed", fd);
+ return ret;
+ }
+#if defined(SO_REUSEPORT)
+ if ((ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)(reuseAddr ? &yes : &no), sizeof(int)))) {
+ TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEPORT, fd=%d) have failed", fd);
+ return ret;
+ }
+#endif
+ return 0;
+ }
+ return -1;
+}
+
+/**@ingroup tnet_utils_group
+ * Sends data to a specific destination.
+ * @param fd The source socket.
+ * @param to The destination socket.
+ * @param buf A pointer to the buffer to send over the network.
+ * @param size The size of the buffer.
+ * @retval If no error occurs, sendto returns the total number of bytes sent, which can be less than the number indicated by @b size.
+ * Otherwise, non-zero (negative) error code is returned.
+ */
+int tnet_sockfd_sendto(tnet_fd_t fd, const struct sockaddr *to, const void* buf, tsk_size_t size)
+{
+ tsk_size_t sent = 0;
+ int ret = -1;
+
+ if (fd == TNET_INVALID_FD) {
+ TSK_DEBUG_ERROR("Using invalid FD to send data.");
+ goto bail;
+ }
+ if (!buf || !size) {
+ TSK_DEBUG_ERROR("Using invalid BUFFER.");
+ ret = -2;
+ goto bail;
+ }
+
+ while (sent < size) {
+ int try_guard = 10;
+#if TNET_UNDER_WINDOWS
+ WSABUF wsaBuffer;
+ DWORD numberOfBytesSent = 0;
+ wsaBuffer.buf = ((CHAR*)buf) + sent;
+ wsaBuffer.len = (ULONG)(size - sent);
+ try_again:
+ ret = WSASendTo(fd, &wsaBuffer, 1, &numberOfBytesSent, 0, to, tnet_get_sockaddr_size(to), 0, 0); // returns zero if succeed
+ if (ret == 0) {
+ ret = numberOfBytesSent;
+ }
+#else
+ try_again:
+ ret = sendto(fd, (((const uint8_t*)buf) + sent), (size - sent), 0, to, tnet_get_sockaddr_size(to)); // returns number of sent bytes if succeed
+#endif
+ if (ret <= 0) {
+ if (tnet_geterrno() == TNET_ERROR_WOULDBLOCK) {
+ TSK_DEBUG_INFO("SendUdp(fd=%d) - WouldBlock. Retrying...", fd);
+ if (try_guard--) {
+ tsk_thread_sleep(10);
+ goto try_again;
+ }
+ }
+ else {
+ TNET_PRINT_LAST_ERROR("sendto(fd=%d) failed", fd);
+ }
+ goto bail;
+ }
+ else {
+ sent += ret;
+ }
+ }
+
+bail:
+ return (int)((size == sent) ? sent : ret);
+}
+
+/**@ingroup tnet_utils_group
+ * Receives a datagram and stores the source address.
+ * @param fd A descriptor identifying a bound socket.
+ * @param buf A buffer for the incoming data.
+ * @param size The length, in bytes, of the buffer pointed to by the buf parameter.
+ * @param flags A set of options that modify the behavior of the function call beyond the options specified for the associated socket.
+ * All flags which can be passed to @b recvfrom.
+ * @param from An optional pointer to a buffer in a @b sockaddr structure that will hold the source address upon return.
+ * If no error occurs, recvfrom returns the number of bytes received. If the connection has been gracefully closed, the return value is zero.
+ * Otherwise, non-zero (negative) error code is returned.
+ */
+int tnet_sockfd_recvfrom(tnet_fd_t fd, void* buf, tsk_size_t size, int flags, struct sockaddr *from)
+{
+ socklen_t fromlen;
+
+ if (fd == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Using invalid FD to recv data.");
+ return -1;
+ }
+
+ fromlen = tnet_get_sockaddr_size(from);
+ return recvfrom(fd, (char*)buf, (int)size, flags, from, &fromlen);
+}
+
+/**@ingroup tnet_utils_group
+ * Sends data on a connected socket.
+ * @param fd A descriptor identifying a connected socket.
+ * @param buf A pointer to a buffer containing the data to be transmitted.
+ * @param size The length, in bytes, of the data in buffer pointed to by the buf parameter.
+ * @param flags A set of flags that specify the way in which the call is made.
+ * All flags which can be passed to @b recv.
+ * @retval If no error occurs, send returns the total number of bytes sent, which can be less than the number requested to be sent in the @b size parameter.
+ */
+tsk_size_t tnet_sockfd_send(tnet_fd_t fd, const void* buf, tsk_size_t size, int flags)
+{
+ int ret = -1;
+ tsk_size_t sent = 0;
+
+ if (fd == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Using invalid FD to send data.");
+ goto bail;
+ }
+
+ while (sent < size){
+ if ((ret = send(fd, (((const char*)buf) + sent), (int)(size - sent), flags)) <= 0){
+ if (tnet_geterrno() == TNET_ERROR_WOULDBLOCK){
+ if ((ret = tnet_sockfd_waitUntilWritable(fd, TNET_CONNECT_TIMEOUT))){
+ break;
+ }
+ else continue;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("send failed");
+ // Under Windows XP if WSAGetLastError()==WSAEINTR then try to disable both the ICS and the Firewall
+ // More info about How to disable the ISC: http://support.microsoft.com/?scid=kb%3Ben-us%3B230112&x=6&y=11
+ goto bail;
+ }
+ }
+ else{
+ sent += ret;
+ }
+ }
+
+bail:
+ //return (size == sent) ? sent : ret;
+ return sent;
+}
+
+/**@ingroup tnet_utils_group
+ * Receives data from a connected socket or a bound connectionless socket.
+ * @param fd The descriptor that identifies a connected socket.
+ * @param buf A pointer to the buffer to receive the incoming data.
+ * @param size The length, in bytes, of the buffer pointed to by the buf parameter.
+ * @param flags A set of flags that influences the behavior of this function.
+ * All flags which can be passed to @b recv.
+ * @retval If no error occurs, recv returns the number of bytes received and the buffer pointed to by the buf parameter will contain this data received. If the connection has been gracefully closed, the return value is zero.
+ * Otherwise, non-zero (negative) error code is returned.
+ */
+int tnet_sockfd_recv(tnet_fd_t fd, void* buf, tsk_size_t size, int flags)
+{
+ int ret = -1;
+
+ if (fd == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Using invalid FD to recv data.");
+ goto bail;
+ }
+
+ if ((ret = (int)recv(fd, (char*)buf, (int)size, flags)) <= 0){
+ TNET_PRINT_LAST_ERROR("recv failed.");
+ goto bail;
+ }
+
+bail:
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+ * Establishes a connection to a specified socket.
+ * @param fd A descriptor identifying an unconnected socket.
+ * @param to A pointer to the @b sockaddr_storage structure to which the connection should be established.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_sockfd_connectto(tnet_fd_t fd, const struct sockaddr_storage *to)
+{
+ int status = -1;
+
+#if TNET_UNDER_WINDOWS
+
+ if ((status = WSAConnect(fd, (LPSOCKADDR)to, sizeof(*to), NULL, NULL, NULL, NULL)) == SOCKET_ERROR){
+ status = WSAGetLastError();
+ if (status == TNET_ERROR_WOULDBLOCK || status == TNET_ERROR_ISCONN || status == TNET_ERROR_INTR || status == TNET_ERROR_INPROGRESS){
+ TSK_DEBUG_WARN("TNET_ERROR_WOULDBLOCK/TNET_ERROR_ISCONN/TNET_ERROR_INTR/TNET_ERROR_INPROGRESS -> you should use tnet_sockfd_waitUntilWritable() before trying to send data");
+ status = 0;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("WSAConnect have failed");
+ }
+ }
+
+#else /* !TNET_UNDER_WINDOWS */
+
+#if TNET_HAVE_SS_LEN
+ if ((status = connect(fd, (struct sockaddr*)to, to->ss_len)))
+# else
+ if((status = connect(fd, (struct sockaddr*)to, sizeof(*to))))
+# endif
+ {
+ status = tnet_geterrno();
+ if(status == TNET_ERROR_WOULDBLOCK || status == TNET_ERROR_ISCONN || status == TNET_ERROR_INPROGRESS || status == TNET_ERROR_EAGAIN){
+ TSK_DEBUG_INFO("TNET_ERROR_WOULDBLOCK/TNET_ERROR_ISCONN/TNET_ERROR_INPROGRESS/TNET_ERROR_EAGAIN ==> use tnet_sockfd_waitUntilWritable.");
+ status = 0;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("connect have failed.");
+ }
+ }
+
+#endif /* TNET_UNDER_WINDOWS */
+
+ return status;
+}
+
+/**@ingroup tnet_utils_group
+ */
+int tnet_sockfd_listen(tnet_fd_t fd, int backlog)
+{
+ if (fd > 0){
+ return listen(fd, backlog);
+ }
+ else return -1;
+}
+
+/**@ingroup tnet_utils_group
+ */
+tnet_fd_t tnet_sockfd_accept(tnet_fd_t fd, struct sockaddr *addr, socklen_t *addrlen)
+{
+ tnet_fd_t ret = TNET_INVALID_FD;
+
+ if (fd > 0){
+ ret = (tnet_fd_t)accept(fd, addr, addrlen);
+ }
+
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+ * Closes an existing socket.
+ * @param fd A descriptor identifying the socket to close.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_sockfd_close(tnet_fd_t *fd)
+{
+ if (*fd != TNET_INVALID_FD){
+ int ret;
+#if TNET_UNDER_WINDOWS
+ ret = closesocket(*fd);
+#else
+ ret = close(*fd);
+#endif
+ TSK_DEBUG_INFO("CloseSocket(%d)", *fd);
+ *fd = TNET_INVALID_FD;
+ return ret;
+ }
+ return 0;
+}
+
+/**@ingroup tnet_utils_group
+ * Disables both receiving and sending functions. Will raise POLLHUP event.
+ * IMPORTANT: The socket still need to be closed.
+ * @param fd A descriptor identifying the socket to shutdown.
+ * @retval Zero if succeed and non-zero error code otherwise.
+ */
+int tnet_sockfd_shutdown(tnet_fd_t fd)
+{
+ return shutdown(fd, 2/*SD_BOTH*/);
+}
+
+/**@ingroup tnet_utils_group
+ */
+tnet_proxy_type_t tnet_proxy_type_from_string(const char* type)
+{
+ if (tsk_striequals(type, "http")) return tnet_proxy_type_http;
+ else if (tsk_striequals(type, "https")) return tnet_proxy_type_https;
+ else if (tsk_striequals(type, "socks4")) return tnet_proxy_type_socks4;
+ else if (tsk_striequals(type, "socks4a")) return tnet_proxy_type_socks4a;
+ else if (tsk_striequals(type, "socks5")) return tnet_proxy_type_socks5;
+ else return tnet_proxy_type_none;
+}
+
+/**@ingroup tnet_utils_group
+ */
+const char* tnet_proxy_type_to_string(tnet_proxy_type_t type)
+{
+ switch (type) {
+ case tnet_proxy_type_http: return "http";
+ case tnet_proxy_type_https: return "https";
+ case tnet_proxy_type_socks4: return "socks4";
+ case tnet_proxy_type_socks4a: return "socks4a";
+ case tnet_proxy_type_socks5: return "socks5";
+ default: return "none";
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//=================================================================================================
+// INTERFACE object definition
+//
+static tsk_object_t* tnet_interface_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_interface_t *iface = (tnet_interface_t *)self;
+ if (iface){
+ const char* description = va_arg(*app, const char*);
+ const void* mac_address = va_arg(*app, const void*);
+ tsk_size_t mac_address_length = va_arg(*app, tsk_size_t);
+
+ iface->description = tsk_strdup(description);
+ if ((iface->mac_address = (uint8_t*)tsk_calloc(mac_address_length, sizeof(uint8_t)))){
+ memcpy(iface->mac_address, mac_address, mac_address_length);
+ }
+ iface->mac_address_length = mac_address_length;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_interface_dtor(tsk_object_t * self)
+{
+ tnet_interface_t *iface = (tnet_interface_t *)self;
+ if (iface){
+ TSK_FREE(iface->description);
+ TSK_FREE(iface->mac_address);
+ }
+
+ return self;
+}
+
+static int tnet_interface_cmp(const tsk_object_t *if1, const tsk_object_t *if2)
+{
+ const tnet_interface_t *iface1 = (const tnet_interface_t *)if1;
+ const tnet_interface_t *iface2 = (const tnet_interface_t *)if2;
+
+ if (iface1 && iface2){
+ return tsk_stricmp(iface1->description, iface1->description);
+ }
+ else if (!iface1 && !iface2) return 0;
+ else return -1;
+}
+
+static const tsk_object_def_t tnet_interface_def_s =
+{
+ sizeof(tnet_interface_t),
+ tnet_interface_ctor,
+ tnet_interface_dtor,
+ tnet_interface_cmp,
+};
+const tsk_object_def_t *tnet_interface_def_t = &tnet_interface_def_s;
+
+
+
+
+//=================================================================================================
+// ADDRESS object definition
+//
+static tsk_object_t* tnet_address_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_address_t *address = (tnet_address_t *)self;
+ if (address){
+ address->ip = tsk_strdup(va_arg(*app, const char*));
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_address_dtor(tsk_object_t * self)
+{
+ tnet_address_t *address = (tnet_address_t *)self;
+ if (address){
+ TSK_FREE(address->ip);
+ }
+
+ return self;
+}
+
+static int tnet_address_cmp(const tsk_object_t *_a1, const tsk_object_t *_a2)
+{
+ const tnet_address_t *a1 = (const tnet_address_t *)_a1;
+ const tnet_address_t *a2 = (const tnet_address_t *)_a2;
+
+ if (a1 && a2){
+ // to have AF_UNSPEC, AF_UNIX, AF_INET, ... first
+ return (a1->family - a2->family);
+ }
+ else if (!a1 && !a2) return 0;
+ else return -1;
+}
+
+static const tsk_object_def_t tnet_address_def_s =
+{
+ sizeof(tnet_address_t),
+ tnet_address_ctor,
+ tnet_address_dtor,
+ tnet_address_cmp,
+};
+const tsk_object_def_t *tnet_address_def_t = &tnet_address_def_s;
+
diff --git a/tinyNET/src/tnet_utils.h b/tinyNET/src/tnet_utils.h
new file mode 100644
index 0000000..6673696
--- /dev/null
+++ b/tinyNET/src/tnet_utils.h
@@ -0,0 +1,186 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 DOUBANGO.
+*
+*/
+
+/**@file tnet_utils.h
+ * @brief Network utility functions.
+ *
+ */
+#ifndef TNET_UTILS_H
+#define TNET_UTILS_H
+
+#include "tinynet_config.h"
+
+#include "tnet_socket.h"
+#include "tnet_types.h"
+
+TNET_BEGIN_DECLS
+
+/**@ingroup tnet_utils_group
+*/
+#if !defined(TNET_CONNECT_TIMEOUT)
+# define TNET_CONNECT_TIMEOUT 2000
+#endif /* TNET_CONNECT_TIMEOUT */
+
+/**Interface.
+*/
+typedef struct tnet_interface_s
+{
+ TSK_DECLARE_OBJECT;
+
+ unsigned index;
+
+ char* description;
+ uint8_t* mac_address;
+ tsk_size_t mac_address_length;
+}
+tnet_interface_t;
+
+
+/**Address.
+*/
+typedef struct tnet_address_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_family_t family;
+
+ unsigned unicast:1;
+ unsigned anycast:1;
+ unsigned multicast:1;
+ unsigned dnsserver:1;
+
+ char* ip;
+}
+tnet_address_t;
+
+TINYNET_API void tnet_getlasterror(tnet_error_t *error);
+TINYNET_API int tnet_geterrno();
+
+TINYNET_API tnet_interfaces_L_t* tnet_get_interfaces();
+TINYNET_API tnet_addresses_L_t* tnet_get_addresses(tnet_family_t family, tsk_bool_t unicast, tsk_bool_t anycast, tsk_bool_t multicast, tsk_bool_t dnsserver, long if_index);
+#define tnet_get_addresses_all() tnet_get_addresses(AF_UNSPEC, 1, 1, 1, 1, -1)
+#define tnet_get_addresses_all_unicast() tnet_get_addresses(AF_UNSPEC, 1, 0, 0, 0, -1)
+#define tnet_get_addresses_unicast4() tnet_get_addresses(AF_INET, 1, 0, 0, 0, -1)
+#define tnet_get_addresses_unicast6() tnet_get_addresses(AF_INET6, 1, 0, 0, 0, -1)
+#define tnet_get_addresses_all_anycast() tnet_get_addresses(AF_UNSPEC, 0, 1, 0, 0, -1)
+#define tnet_get_addresses_anycast4() tnet_get_addresses(AF_INET, 0, 1, 0, 0, -1)
+#define tnet_get_addresses_anycast6() tnet_get_addresses(AF_INET6, 0, 1, 0, 0, -1)
+#define tnet_get_addresses_all_multicast() tnet_get_addresses(AF_UNSPEC, 0, 0, 1, 0, -1)
+#define tnet_get_addresses_multicast4() tnet_get_addresses(AF_INET, 0, 0, 1, 0, -1)
+#define tnet_get_addresses_multicast6() tnet_get_addresses(AF_INET6, 0, 0, 1, 0, -1)
+#define tnet_get_addresses_all_dnsservers() tnet_get_addresses(AF_UNSPEC, 0, 0, 0, 1, -1)
+#define tnet_get_addresses_dnsservers4() tnet_get_addresses(AF_INET, 0, 0, 0, 1, -1)
+#define tnet_get_addresses_dnsservers6() tnet_get_addresses(AF_INET6, 0, 0, 0, 1, -1)
+TINYNET_API int tnet_get_mac_address(tnet_mac_address* address);
+
+TINYNET_API int tnet_getbestsource(const char* destination, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t *source);
+TINYNET_API int tnet_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
+TINYNET_API void tnet_freeaddrinfo(struct addrinfo *ai);
+TINYNET_API int tnet_getsockname(tnet_fd_t fd, struct sockaddr_storage *result);
+TINYNET_API int tnet_getpeername(tnet_fd_t fd, struct sockaddr_storage *result);
+TINYNET_API tnet_socket_type_t tnet_get_socket_type(tnet_fd_t fd);
+TINYNET_API tnet_family_t tnet_get_family(const char* host, tnet_port_t port);
+TINYNET_API int tnet_get_ip_n_port(tnet_fd_t fd, tsk_bool_t getlocal, tnet_ip_t *ip, tnet_port_t *port);
+TINYNET_API int tnet_get_sockip_n_port(const struct sockaddr *addr, tnet_ip_t *ip, tnet_port_t *port);
+TINYNET_API int tnet_get_peerip_n_port(tnet_fd_t localFD, tnet_ip_t *ip, tnet_port_t *port);
+#define tnet_get_ip(fd, getlocal, ip) tnet_get_ip_n_port(fd, getlocal, ip, 0)
+#define tnet_get_port(fd, getlocal, port) tnet_get_ip_n_port(fd, getlocal, tsk_null, port)
+#define tnet_get_sockip(addr, ip) tnet_get_sockip_n_port(addr, ip, 0)
+#define tnet_get_sockport(addr, port) tnet_get_sockip_n_port(addr, 0, port)
+#define tnet_get_peerip(localFD, ip) tnet_get_peerip_n_port(localFD, ip, 0)
+#define tnet_get_peerport(localFD, port) tnet_get_peerip_n_port(localFD, 0, port)
+
+#if TNET_HAVE_SA_LEN
+# define tnet_get_sockaddr_size(psockaddr) (psockaddr)->sa_len
+#else
+# define tnet_get_sockaddr_size(psockaddr) ((psockaddr)->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6): ((psockaddr)->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(*(psockaddr))))
+#endif
+
+#if TNET_UNDER_WINDOWS
+# define tnet_ioctlt ioctlsocket /* FIXME: use WSAIoctl */
+# define tnet_soccket(family, type, protocol) WSASocket((family), (type), (protocol), NULL, 0, WSA_FLAG_OVERLAPPED)
+#else
+# define tnet_ioctlt ioctl
+# define tnet_soccket(family, type, protocol) socket((family), (type), (protocol))
+#endif
+
+TINYNET_API int tnet_get_fd_max_allowed(tsk_size_t* size);
+TINYNET_API int tnet_set_fd_max_allowed(tsk_size_t size);
+TINYNET_API int tnet_get_fd_opened_count(tsk_size_t* count);
+
+TINYNET_API int tnet_getnameinfo(const struct sockaddr *sa, socklen_t salen, char* node, socklen_t nodelen, char* service, socklen_t servicelen, int flags);
+TINYNET_API int tnet_gethostname(tnet_host_t* result);
+
+TINYNET_API int tnet_inet_pton(int af, const char* src, void* dst);
+TINYNET_API const char *tnet_inet_ntop(int af, const void *src, char * dst, int size);
+
+TINYNET_API int tnet_sockfd_waitUntil(tnet_fd_t fd, long timeout, tsk_bool_t writable);
+#define tnet_sockfd_waitUntilWritable(fd, timeout) tnet_sockfd_waitUntil(fd, timeout, tsk_true)
+#define tnet_sockfd_waitUntilReadable(fd, timeout) tnet_sockfd_waitUntil(fd, timeout, tsk_false)
+TINYNET_API int tnet_sockfd_joingroup6(tnet_fd_t fd, const char* multiaddr, unsigned iface_index);
+TINYNET_API int tnet_sockfd_leavegroup6(tnet_fd_t fd, const char* multiaddr, unsigned iface_index);
+
+TINYNET_API int tnet_resolve(const char *fqdn, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t* out_ip, tnet_port_t* out_port);
+
+TINYNET_API int tnet_sockaddrinfo_init(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *ai_addr, int *ai_family, int *ai_socktype, int *ai_protocol);
+TINYNET_API int tnet_sockaddr_init(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *addr);
+TINYNET_API int tnet_sockfd_init(const char *host, tnet_port_t port, tnet_socket_type_t type, tnet_fd_t *fd);
+
+TINYNET_API int tnet_sockfd_set_mode(tnet_fd_t fd, int nonBlocking);
+TINYNET_API int tnet_sockfd_reuseaddr(tnet_fd_t fd, int reuseAddr);
+#define tnet_sockfd_set_nonblocking(fd) tnet_sockfd_set_mode(fd, 1)
+#define tnet_sockfd_set_blocking(fd) tnet_sockfd_set_mode(fd, 0)
+
+TINYNET_API int tnet_sockfd_sendto(tnet_fd_t fd, const struct sockaddr *to, const void* buf, tsk_size_t size);
+TINYNET_API int tnet_sockfd_recvfrom(tnet_fd_t fd, void* buf, tsk_size_t size, int flags, struct sockaddr *from);
+TINYNET_API tsk_size_t tnet_sockfd_send(tnet_fd_t fd, const void* buf, tsk_size_t size, int flags);
+TINYNET_API int tnet_sockfd_recv(tnet_fd_t fd, void* buf, tsk_size_t size, int flags);
+TINYNET_API int tnet_sockfd_connectto(tnet_fd_t fd, const struct sockaddr_storage *to);
+TINYNET_API int tnet_sockfd_listen(tnet_fd_t fd, int backlog);
+TINYNET_API tnet_fd_t tnet_sockfd_accept(tnet_fd_t fd, struct sockaddr *addr, socklen_t *addrlen);
+
+TINYNET_API int tnet_sockfd_close(tnet_fd_t *fd);
+TINYNET_API int tnet_sockfd_shutdown(tnet_fd_t fd);
+
+TINYNET_API tnet_proxy_type_t tnet_proxy_type_from_string(const char* type);
+TINYNET_API const char* tnet_proxy_type_to_string(tnet_proxy_type_t type);
+
+/**Prints last network error to @b stderr.
+*/
+#define TNET_PRINT_LAST_ERROR(FMT, ...) \
+ { \
+ tnet_error_t error; \
+ tnet_getlasterror(&error); \
+ TSK_DEBUG_ERROR(FMT, ##__VA_ARGS__); \
+ TSK_DEBUG_ERROR("(SYSTEM)NETWORK ERROR ==>%s", error) \
+ }
+
+
+tnet_interface_t* tnet_interface_create(const char* description, const void* mac_address, tsk_size_t mac_address_length);
+tnet_address_t* tnet_address_create(const char* ip);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_interface_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_address_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_UTILS_H */
+
+
diff --git a/tinyNET/src/turn/tnet_turn.c b/tinyNET/src/turn/tnet_turn.c
new file mode 100644
index 0000000..0f38d02
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn.c
@@ -0,0 +1,701 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_turn.c
+// * @brief Traversal Using Relays around NAT (TURN) implementation as per 'draft-ietf-behave-turn-16', 'draft-ietf-behave-turn-tcp-05'
+// * and 'draft-ietf-behave-turn-ipv6'.
+// * http://tools.ietf.org/html/draft-ietf-behave-turn-16
+// * http://tools.ietf.org/html/draft-ietf-behave-turn-tcp-05
+// * http://tools.ietf.org/html/draft-ietf-behave-turn-ipv6-07
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#include "tnet_turn.h"
+//
+//#include "tnet_turn_message.h"
+//
+//#include "tsk_string.h"
+//#include "tsk_memory.h"
+//
+//#include "../tnet_nat.h"
+//#include "../tnet_utils.h"
+//#include "../tnet_endianness.h"
+//
+//#include "tsk_md5.h"
+//#include "tsk_debug.h"
+//
+//#include <string.h>
+//
+///**@defgroup tnet_turn_group TURN(draft-ietf-behave-turn-16) implementation.
+//*/
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_turn_channel_binding_t* tnet_turn_channel_binding_create(const tnet_turn_allocation_t *allocation)
+//{
+// return tsk_object_new(tnet_turn_channel_binding_def_t, allocation);
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_turn_permission_t* tnet_turn_permission_create(uint32_t timeout)
+//{
+// return tsk_object_new(tnet_turn_permission_def_t, timeout);
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_turn_allocation_t* tnet_turn_allocation_create(tnet_fd_t fd, tnet_socket_type_t socket_type, const char* server_address, tnet_port_t server_port, const char* username, const char* password)
+//{
+// return tsk_object_new(tnet_turn_allocation_def_t, fd, socket_type, server_address, server_port, username, password);
+//}
+//
+///*
+//- IMPORTANT: 16. Detailed Example
+//- It is suggested that the client refresh the allocation roughly 1 minute before it expires.
+//- If the client wishes to immediately delete an existing allocation, it includes a LIFETIME attribute with a value of 0.
+//*/
+//
+//typedef tnet_stun_pkt_req_t* (*tnet_turn_create_request_func)(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app);
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_stun_pkt_req_t* tnet_turn_create_request(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, tnet_stun_pkt_type_t type)
+//{
+// tnet_stun_attr_t* attribute;
+// tnet_stun_pkt_req_t *request = tnet_stun_message_create(context->username, context->password);
+//
+// if(request){
+// request->type = type;
+//
+// request->fingerprint = context->enable_fingerprint;
+// request->integrity = context->enable_integrity;
+// request->nointegrity = !request->integrity;
+// request->dontfrag = context->enable_dontfrag;
+// request->realm = tsk_strdup(allocation->realm);
+// request->nonce = tsk_strdup(allocation->nonce);
+//
+// /* Create random transaction id */
+// {
+// tsk_istr_t random;
+// tsk_md5digest_t digest;
+//
+// tsk_strrandom(&random);
+// TSK_MD5_DIGEST_CALC(random, sizeof(random), digest);
+//
+// memcpy(request->transac_id, digest, TNET_STUN_TRANSACID_SIZE);
+// }
+//
+// /* Add software attribute */
+// if(allocation->software){
+// attribute = (tnet_stun_attr_t*)tnet_stun_attribute_software_create(allocation->software, tsk_strlen(allocation->software));
+// tnet_stun_message_add_attribute(request, &attribute);
+// }
+// }
+//
+// return request;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_stun_pkt_req_t* tnet_turn_create_request_allocate(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+//{
+// tnet_stun_pkt_req_t* request = tnet_turn_create_request(context, allocation, stun_allocate_request);
+// if(request){
+// tnet_stun_attr_t* attribute;
+//
+// /* Add Requested transport. */
+// if((attribute = (tnet_stun_attr_t*)tnet_turn_attribute_reqtrans_create(TNET_SOCKET_TYPE_IS_DGRAM(allocation->socket_type) ? TNET_PROTO_UDP: TNET_PROTO_TCP))){
+// tnet_stun_message_add_attribute(request, &attribute);
+// }
+//
+// /* Add lifetime */
+// if((attribute = (tnet_stun_attr_t*)tnet_turn_attribute_lifetime_create(tnet_ntohl(allocation->timeout)))){
+// tnet_stun_message_add_attribute(request, &attribute);
+// }
+//
+// /* Add Event Port */
+// if(context->enable_evenport && (attribute = (tnet_stun_attr_t*)tnet_turn_attribute_even_port_create(context->enable_evenport))){
+// tnet_stun_message_add_attribute(request, &attribute);
+// }
+// }
+//
+// return request;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_stun_pkt_req_t* tnet_turn_create_request_refresh(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+//{
+// tnet_stun_pkt_req_t *request = tnet_turn_create_request_allocate(context, allocation, app);
+// if(request){
+// request->type = stun_refresh_request;
+// }
+// return request;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_stun_pkt_req_t* tnet_turn_create_request_unallocate(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+//{
+// tnet_stun_pkt_req_t *request = tnet_turn_create_request_refresh(context, allocation, app);
+// if(request){
+// ((tnet_turn_attribute_lifetime_t*)tnet_stun_message_get_attribute(request, stun_lifetime))->value = 0;
+// }
+// return request;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_stun_pkt_req_t* tnet_turn_create_request_channel_bind(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+//{
+// tnet_stun_pkt_req_t* request = tnet_turn_create_request(context, allocation, stun_channelbind_request);
+// if(request){
+// const tnet_turn_channel_binding_t* channel_binding;
+// tnet_turn_attribute_t *attribute;
+// tnet_turn_channel_binding_id_t number;
+// uint32_t lifetime;
+//
+//
+// channel_binding = va_arg(*app, const tnet_turn_channel_binding_t *);
+// number = tnet_htons(channel_binding->id);
+// lifetime = tnet_htonl(channel_binding->timeout);
+// attribute = tsk_object_ref(channel_binding->xpeer);
+//
+// /* XOR-PEER */
+// tnet_stun_message_add_attribute(request, &attribute);
+//
+// /* CHANNEL-NUMBER */
+// if((attribute = (tnet_stun_attr_t*)tnet_turn_attribute_channelnum_create(number))){
+// tnet_stun_message_add_attribute(request, &attribute);
+// }
+//
+// /* LIFETIME */
+// if((attribute = (tnet_stun_attr_t*)tnet_turn_attribute_lifetime_create(lifetime))){
+// tnet_stun_message_add_attribute(request, &attribute);
+// }
+// }
+// return request;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_stun_pkt_req_t* tnet_turn_create_request_channel_refresh(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+//{
+// return tnet_turn_create_request_channel_bind(context, allocation, app);
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_stun_pkt_req_t* tnet_turn_create_request_sendindication(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+//{
+// tnet_stun_pkt_req_t* request = tnet_turn_create_request(context, allocation, stun_send_indication);
+// if(request){
+// tnet_turn_attribute_t *attribute;
+// tnet_turn_attribute_xpeer_addr_t* xpeer = tsk_object_ref(va_arg(*app, tnet_turn_attribute_xpeer_addr_t *));
+// const void* data = va_arg(*app, const void *);
+// tsk_size_t size = va_arg(*app, tsk_size_t);
+//
+// /*
+// draft-ietf-behave-turn-16 - 10.1. Forming a Send Indication
+//
+// When forming a Send indication, the client MUST include a XOR-PEER-
+// ADDRESS attribute and a DATA attribute. The XOR-PEER-ADDRESS
+// attribute contains the transport address of the peer to which the
+// data is to be sent, and the DATA attribute contains the actual
+// application data to be sent to the peer.
+// */
+//
+// /* XOR-PEER-ADDRESS */
+// tnet_stun_message_add_attribute(request, (tnet_turn_attribute_t**)&xpeer);
+//
+// /* DATA */
+// if((attribute = (tnet_stun_attr_t*)tnet_turn_attribute_data_create(data, size))){
+// tnet_stun_message_add_attribute(request, &attribute);
+// }
+// }
+// return request;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_stun_pkt_req_t* tnet_turn_create_request_permission(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+//{
+// tnet_stun_pkt_req_t* request = tnet_turn_create_request(context, allocation, stun_createpermission_request);
+// if(request){
+// //--const char* ipaddress = va_arg(*app, const char *);
+//
+// /* XOR-PEER-ADDRESS */
+// tnet_turn_attribute_xpeer_addr_t* attribute = tnet_turn_attribute_xpeer_addr_create_null();
+// attribute->family = stun_ipv4;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 8;
+//
+// attribute->xaddress[0] = 0x79;
+// attribute->xaddress[1] = 0xA1;
+// attribute->xaddress[2] = 0x83;
+// attribute->xaddress[3] = 0x47;
+//
+// tnet_stun_message_add_attribute(request, (tnet_stun_attr_t**)&attribute);
+//
+// /*if((attribute = tnet_turn_attribute_even_port_create(context->enable_evenport)))
+// {
+// tnet_stun_message_add_attribute(request, &attribute);
+// }*/
+// }
+// return request;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//int tnet_turn_send_request(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, tnet_turn_create_request_func funcptr, ...)
+//{
+// tnet_stun_pkt_req_t *request;
+// int ret = -1;
+// va_list ap;
+//
+// va_start(ap, funcptr);
+// request = funcptr(context, allocation, &ap);
+// va_end(ap);
+//
+// if(request){
+// if(TNET_SOCKET_TYPE_IS_DGRAM(allocation->socket_type)){
+// tnet_stun_pkt_resp_t *response = tnet_stun_send_unreliably(allocation->localFD, 500, 7, request, (struct sockaddr*)&allocation->server);
+// if(response)
+// {
+// if(TNET_STUN_PKT_RESP_IS_ERROR(response)){
+// short code = tnet_stun_message_get_errorcode(response);
+// const char* realm = tnet_stun_message_get_realm(response);
+// const char* nonce = tnet_stun_message_get_nonce(response);
+//
+// if(code == 401 && realm && nonce){
+// if(!allocation->nonce)
+// { /* First time we get a nonce */
+// tsk_strupdate(&allocation->nonce, nonce);
+// tsk_strupdate(&allocation->realm, realm);
+//
+// /* Delete the message and response before retrying*/
+// TSK_OBJECT_SAFE_FREE(response);
+// TSK_OBJECT_SAFE_FREE(request);
+//
+// // Send again using new transaction identifier
+// return tnet_turn_send_request(context, allocation, funcptr);
+// }
+// else{
+// ret = -3;
+// }
+// }
+// else
+// {
+// TSK_DEBUG_ERROR("Server error code: %d", code);
+// ret = -2;
+// }
+// }
+// else /* Any (allocate, permission, channel binding ...) success response */
+// {
+// if(response->type == stun_allocate_success_response) /* Allocate success response */
+// {
+// /* LifeTime */
+// {
+// int32_t lifetime = tnet_stun_message_get_lifetime(response);
+// if(lifetime>=0)
+// {
+// allocation->timeout = lifetime;
+// }
+// }
+// /* STUN mapped or xmapped address */
+// {
+// const tnet_stun_attr_t *attribute;
+// if((attribute = tnet_stun_message_get_attribute(response, stun_xor_mapped_address)))
+// {
+// allocation->xmaddr = tsk_object_ref((void*)attribute);
+// }
+// else if((attribute= tnet_stun_message_get_attribute(response, stun_mapped_address)))
+// {
+// allocation->maddr = tsk_object_ref((void*)attribute);
+// }
+// }
+// }
+//
+// /* Set ret to zero (success) */
+// ret = 0;
+// }
+// }
+// else{
+// ret = -4;
+// }
+// TSK_OBJECT_SAFE_FREE(response);
+// }
+// }
+//
+// TSK_OBJECT_SAFE_FREE(request);
+// return ret;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_turn_allocation_id_t tnet_turn_allocate(const tnet_nat_context_t* nat_context, const tnet_fd_t localFD, tnet_socket_type_t socket_type)
+//{
+// tnet_turn_allocation_id_t id = TNET_TURN_INVALID_ALLOCATION_ID;
+//
+// if(nat_context){
+// int ret;
+// tnet_turn_allocation_t* allocation = tnet_turn_allocation_create(localFD, nat_context->socket_type, nat_context->server_address, nat_context->server_port, nat_context->username, nat_context->password);
+// allocation->software = tsk_strdup(nat_context->software);
+//
+// if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_allocate))){
+// TSK_DEBUG_ERROR("TURN allocation failed with error code:%d.", ret);
+// TSK_OBJECT_SAFE_FREE(allocation);
+// }
+// else{
+// id = allocation->id;
+// tsk_list_push_back_data(nat_context->allocations, (void**)&allocation);
+// }
+// }
+//
+// return id;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//int tnet_turn_allocation_refresh(const struct struct tnet_nat_ctx_s* nat_context, tnet_turn_allocation_t *allocation)
+//{
+// if(nat_context && allocation){
+// int ret;
+//
+// if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_refresh))){
+// TSK_DEBUG_ERROR("TURN allocation refresh failed with error code:%d.", ret);
+// return -1;
+// }
+// else{
+// return 0;
+// }
+// }
+// return -1;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//int tnet_turn_unallocate(const tnet_nat_context_t* nat_context, tnet_turn_allocation_t *allocation)
+//{
+// if(nat_context && allocation){
+// int ret;
+//
+// if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_unallocate))){
+// TSK_DEBUG_ERROR("TURN unallocation failed with error code:%d.", ret);
+// return -1;
+// }
+// else{
+// tsk_list_remove_item_by_data(nat_context->allocations, allocation);
+// return 0;
+// }
+// }
+// return -1;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_turn_channel_binding_id_t tnet_turn_channel_bind(const tnet_nat_context_t* nat_context, tnet_turn_allocation_t *allocation, struct sockaddr_storage *peer)
+//{
+// tnet_turn_channel_binding_id_t id = TNET_TURN_INVALID_CHANNEL_BINDING_ID;
+// tnet_turn_channel_binding_t *channel_binding = 0;
+//
+// if(nat_context && allocation){
+// int ret;
+//
+// channel_binding = tnet_turn_channel_binding_create(allocation);
+//
+// if(channel_binding){
+// if(((struct sockaddr*)peer)->sa_family == AF_INET){
+// struct sockaddr_in *sin = ((struct sockaddr_in*)peer);
+// uint32_t _sin_addr;
+//
+// channel_binding->xpeer = tnet_turn_attribute_xpeer_addr_create_null();
+// channel_binding->xpeer->family = stun_ipv4;
+// channel_binding->xpeer->xport = ((sin->sin_port) ^ tnet_htons(0x2112));
+//
+// _sin_addr = tnet_htonl_2(&sin->sin_addr) ^tnet_htonl(kStunMagicCookieLong);
+// memcpy(channel_binding->xpeer->xaddress, &_sin_addr, sizeof(_sin_addr));
+// }
+// else if(((struct sockaddr*)peer)->sa_family == AF_INET6){
+// TSK_DEBUG_ERROR("IPv6 not supported.");
+// goto bail;
+// }
+// else{
+// TSK_DEBUG_ERROR("Invalid address family.");
+// goto bail;
+// }
+// }
+// else{
+// goto bail;
+// }
+//
+// if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_channel_bind, channel_binding))){
+// TSK_DEBUG_ERROR("TURN (CHANNEL-BIND) failed with error code:%d.", ret);
+// TSK_OBJECT_SAFE_FREE(channel_binding);
+//
+// goto bail;
+// }
+// else{
+// id = channel_binding->id;
+// tsk_list_push_back_data(allocation->channel_bindings, (void**)&channel_binding);
+// }
+// }
+//
+//bail:
+// TSK_OBJECT_SAFE_FREE(channel_binding);
+// return id;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//int tnet_turn_channel_refresh(const struct struct tnet_nat_ctx_s* nat_context, const tnet_turn_channel_binding_t * channel_bind)
+//{
+// if(nat_context && channel_bind){
+// int ret;
+//
+// if((ret = tnet_turn_send_request(nat_context, (tnet_turn_allocation_t*)channel_bind->allocation, tnet_turn_create_request_channel_refresh, channel_bind))){
+// TSK_DEBUG_ERROR("TURN channel-binding refresh failed with error code:%d.", ret);
+// return -1;
+// }
+// else return 0;
+// }
+// return -1;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//int tnet_turn_channel_senddata(const struct struct tnet_nat_ctx_s* nat_context, const tnet_turn_channel_binding_t * channel_bind, const void* data, tsk_size_t size, int indication)
+//{
+// tnet_turn_channel_data_t *channel_data = 0;
+// tsk_buffer_t *output = 0;
+//
+// int ret = -1;
+//
+// if(nat_context && channel_bind)
+// {
+// if(indication)
+// { /* SEND INDICATION */
+// if((ret = tnet_turn_send_request(nat_context, (tnet_turn_allocation_t*)channel_bind->allocation, tnet_turn_create_request_sendindication, channel_bind->xpeer, data, size)))
+// {
+// TSK_DEBUG_ERROR("TURN channel send indication failed with error code:%d.", ret);
+// return -1;
+// }
+// else return 0;
+// }
+// else
+// { /* CHANNEL DATA */
+// if(!(channel_data = tnet_turn_channel_data_create(channel_bind->id, size, data)))
+// {
+// TSK_DEBUG_ERROR("Failed to create TURN CHANNEL-DATA message.");
+// goto bail;
+// }
+//
+// if(!(output = tnet_turn_channel_data_serialize(channel_data)))
+// {
+// TSK_DEBUG_ERROR("Failed to serialize TURN CHANNEL-DATA.");
+// goto bail;
+// }
+//
+// if(tnet_sockfd_sendto(channel_bind->allocation->localFD, (struct sockaddr*)&channel_bind->allocation->server, output->data, output->size) <= 0)
+// {
+// TNET_PRINT_LAST_ERROR("Failed to send TURN messsage.");
+// ret = -2;
+// goto bail;
+// }
+// else
+// {
+// ret = 0;
+// }
+// }
+// }
+//bail:
+// TSK_OBJECT_SAFE_FREE(channel_data);
+// TSK_OBJECT_SAFE_FREE(output);
+//
+// return ret;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//int tnet_turn_add_permission(const tnet_nat_context_t* nat_context, tnet_turn_allocation_t *allocation, const char* ipaddress, uint32_t timeout)
+//{
+// if(nat_context && allocation)
+// {
+// int ret;
+//
+// if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_permission, ipaddress)))
+// {
+// TSK_DEBUG_ERROR("TURN (ADD) permission failed with error code:%d.", ret);
+// return -1;
+// }
+// else
+// {
+// //tnet_turn_permission_t *permission = tnet_turn_permission_create(timeout);
+// //tsk_list_remove_item_by_data(context->allocations, allocation);
+// return 0;
+// }
+// }
+// return -1;
+//}
+//
+////=================================================================================================
+//// TURN CHANNEL-BINDING object definition
+////
+//static tsk_object_t* tnet_turn_channel_binding_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_channel_binding_t *channel_binding = self;
+// if(channel_binding){
+// static tnet_turn_channel_binding_id_t __allocation_unique_id = 0x4000; /* 0x4000 through 0x7FFF */
+//
+// channel_binding->id = __allocation_unique_id++;
+// channel_binding->allocation = va_arg(*app, const tnet_turn_allocation_t *);
+// channel_binding->timeout = TNET_TURN_CHANBIND_TIMEOUT_DEFAULT; /* 10 minutes as per draft-ietf-behave-turn-16 subclause 11 */
+//
+// if(__allocation_unique_id >= 0x7FFF){
+// __allocation_unique_id = 0x4000;
+// }
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_channel_binding_dtor(tsk_object_t * self)
+//{
+// tnet_turn_channel_binding_t *channel_binding = self;
+// if(channel_binding){
+// TSK_OBJECT_SAFE_FREE(channel_binding->xpeer);
+// }
+//
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_channel_binding_def_s =
+//{
+// sizeof(tnet_turn_channel_binding_t),
+// tnet_turn_channel_binding_ctor,
+// tnet_turn_channel_binding_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_channel_binding_def_t = &tnet_turn_channel_binding_def_s;
+//
+////=================================================================================================
+//// TURN PERMISSION object definition
+////
+//static tsk_object_t* tnet_turn_permission_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_permission_t *permission = self;
+// if(permission){
+// permission->timeout = va_arg(*app, uint32_t);
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_permission_dtor(tsk_object_t * self)
+//{
+// tnet_turn_permission_t *permission = self;
+// if(permission){
+// TSK_OBJECT_SAFE_FREE(permission->xpeer);
+// }
+//
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_permission_def_s =
+//{
+// sizeof(tnet_turn_permission_t),
+// tnet_turn_permission_ctor,
+// tnet_turn_permission_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_permission_def_t = &tnet_turn_permission_def_s;
+//
+//
+//
+////=================================================================================================
+//// TURN ALLOCATION object definition
+////
+//static tsk_object_t* tnet_turn_allocation_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_allocation_t *allocation = self;
+// if(allocation){
+// static tnet_turn_allocation_id_t __allocation_unique_id = 0;
+//
+// const char* server_address;
+// tnet_port_t server_port;
+//
+// allocation->id = ++__allocation_unique_id;
+//
+// allocation->localFD = va_arg(*app, tnet_fd_t);
+// allocation->socket_type = va_arg(*app, tnet_socket_type_t);
+//
+// server_address = va_arg(*app, const char*);
+//#if defined(__GNUC__)
+// server_port = (tnet_port_t)va_arg(*app, unsigned);
+//#else
+// server_port = va_arg(*app, tnet_port_t);
+//#endif
+//
+// allocation->username = tsk_strdup(va_arg(*app, const char*));
+// allocation->password = tsk_strdup(va_arg(*app, const char*));
+//
+// tnet_sockaddr_init(server_address, server_port, allocation->socket_type, &allocation->server);
+// allocation->timeout = 600;
+//
+// allocation->channel_bindings = tsk_list_create();
+// allocation->permissions = tsk_list_create();
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_allocation_dtor(tsk_object_t * self)
+//{
+// tnet_turn_allocation_t *allocation = self;
+// if(allocation){
+// TSK_FREE(allocation->relay_address);
+//
+// TSK_FREE(allocation->username);
+// TSK_FREE(allocation->password);
+// TSK_FREE(allocation->realm);
+// TSK_FREE(allocation->nonce);
+//
+// TSK_FREE(allocation->software);
+//
+// TSK_OBJECT_SAFE_FREE(allocation->xmaddr);
+// TSK_OBJECT_SAFE_FREE(allocation->maddr);
+//
+// TSK_OBJECT_SAFE_FREE(allocation->channel_bindings);
+// TSK_OBJECT_SAFE_FREE(allocation->permissions);
+// }
+//
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_allocation_def_s =
+//{
+// sizeof(tnet_turn_allocation_t),
+// tnet_turn_allocation_ctor,
+// tnet_turn_allocation_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_allocation_def_t = &tnet_turn_allocation_def_s;
+//
diff --git a/tinyNET/src/turn/tnet_turn.h b/tinyNET/src/turn/tnet_turn.h
new file mode 100644
index 0000000..af3a5e4
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn.h
@@ -0,0 +1,175 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_turn.h
+// * @brief Traversal Using Relays around NAT (TURN) implementation as per 'draft-ietf-behave-turn-16', 'draft-ietf-behave-turn-tcp-05'
+// * and 'draft-ietf-behave-turn-ipv6'.
+// * http://tools.ietf.org/html/draft-ietf-behave-turn-16
+// * http://tools.ietf.org/html/draft-ietf-behave-turn-tcp-05
+// * http://tools.ietf.org/html/draft-ietf-behave-turn-ipv6-07
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#ifndef TNET_TURN_H
+//#define TNET_TURN_H
+//
+//#include "tinynet_config.h"
+//
+//#include "turn/tnet_turn_attribute.h"
+//
+//#include "tnet_proto.h"
+//#include "tnet_socket.h"
+//#include "tnet_types.h"
+//
+//#include "tsk_object.h"
+//
+///**@ingroup tnet_turn_group
+//* @def TNET_TURN_PERMISSION_TIMEOUT_DEFAULT
+//*/
+///**@ingroup tnet_turn_group
+//* @def TNET_TURN_CHANBIND_TIMEOUT_DEFAULT
+//*/
+//TNET_BEGIN_DECLS
+//
+//#define TNET_TURN_PERMISSION_TIMEOUT_DEFAULT 300 /* draft-ietf-behave-turn-16 subclause 8 */
+//#define TNET_TURN_CHANBIND_TIMEOUT_DEFAULT 600 /* draft-ietf-behave-turn-16 subclause 11 */
+//
+//
+///**@ingroup tnet_turn_group
+//* @def tnet_turn_allocation_id_t.
+//*/
+///**@ingroup tnet_turn_group
+//* @def TNET_TURN_INVALID_ALLOCATION_ID.
+//*/
+///**@ingroup tnet_turn_group
+//* @def TNET_TURN_IS_VALID_ALLOCATION_ID.
+//*/
+//typedef uint64_t tnet_turn_allocation_id_t;
+//#define TNET_TURN_INVALID_ALLOCATION_ID 0
+//#define TNET_TURN_IS_VALID_ALLOCATION_ID(id) (id != TNET_TURN_INVALID_ALLOCATION_ID)
+//
+///**@ingroup tnet_turn_group
+//* @def tnet_turn_channel_binding_id_t.
+//*/
+///**@ingroup tnet_turn_group
+//* @def TNET_TURN_INVALID_CHANNEL_BINDING_ID.
+//*/
+///**@ingroup tnet_turn_group
+//* @def TNET_TURN_IS_VALID_CHANNEL_BINDING_ID.
+//*/
+//typedef uint16_t tnet_turn_channel_binding_id_t;
+//#define TNET_TURN_INVALID_CHANNEL_BINDING_ID 0x00
+//#define TNET_TURN_IS_VALID_CHANNEL_BINDING_ID(id) ( (0x4000 <= id) && (id <= 0x7FFF) ) /* see draft-ietf-behave-turn-16 subcaluse 11. */
+//
+///**@ingroup tnet_turn_group
+//*/
+//typedef struct tnet_turn_permission_s
+//{
+// TSK_DECLARE_OBJECT;
+//
+// tnet_turn_attribute_xpeer_addr_t *xpeer;
+// uint32_t timeout; /**< Timeout value in seconds. Default is 300s(5 minutes). */
+//}
+//tnet_turn_permission_t;
+//typedef tsk_list_t tnet_turn_permissions_L_t; /**< List of @ref tnet_turn_permission_t elements. */
+//
+///**@ingroup tnet_turn_group
+//*/
+//typedef struct tnet_turn_channel_binding_s
+//{
+// TSK_DECLARE_OBJECT;
+//
+// tnet_turn_channel_binding_id_t id;
+// const struct tnet_turn_allocation_s *allocation;
+// tnet_turn_attribute_xpeer_addr_t *xpeer;
+// uint32_t timeout; /**< Timeout value in seconds. Default is 600s(10 minutes). */
+//}
+//tnet_turn_channel_binding_t;
+//typedef tsk_list_t tnet_turn_channel_bindings_L_t; /**< List of @ref tnet_turn_channel_binding_t elements. */
+//
+///**@ingroup tnet_turn_group
+//*/
+//typedef struct tnet_turn_allocation_s
+//{
+// TSK_DECLARE_OBJECT;
+//
+// tnet_turn_allocation_id_t id; /**< Unique id. */
+//
+// char* relay_address; /**< the relayed transport address */
+// //! Server reflexive address of the local socket(STUN1 as per RFC 3489).
+// tnet_stun_attribute_mapped_addr_t *maddr;
+// //! XORed server reflexive address (STUN2 as per RFC 5389).
+// tnet_stun_attribute_xmapped_addr_t *xmaddr;
+//
+// /* 5-tuple */
+// tnet_fd_t localFD;
+// tnet_socket_type_t socket_type;
+//
+// struct sockaddr_storage server;
+//
+// /*---*/
+//
+// /* the authentication information */
+// char* username;
+// char* password;
+// char* realm;
+// char* nonce;
+// /*---*/
+//
+// /* the time-to-expiry */
+// uint32_t timeout; /**< Timeout value in seconds. Default is 600s(10 minutes). */
+// /*---*/
+//
+// /* A list of permissions */
+// /* A list of channel to peer bindings */
+//
+// char* software;
+//
+// tnet_turn_channel_bindings_L_t *channel_bindings;
+// tnet_turn_permissions_L_t *permissions;
+//}
+//tnet_turn_allocation_t;
+//typedef tsk_list_t tnet_turn_allocations_L_t; /**< List of @ref tnet_turn_allocation_t elements. */
+//
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_permission_def_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_channel_binding_def_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_allocation_def_t;
+//
+////#if defined(__SYMBIAN32__) || ANDROID /* Forward declaration */
+//struct struct tnet_nat_ctx_s;
+////#endif
+//
+//tnet_turn_allocation_id_t tnet_turn_allocate(const struct struct tnet_nat_ctx_s* nat_context, const tnet_fd_t localFD, tnet_socket_type_t socket_type);
+//int tnet_turn_allocation_refresh(const struct struct tnet_nat_ctx_s* nat_context, tnet_turn_allocation_t *allocation);
+//int tnet_turn_unallocate(const struct struct tnet_nat_ctx_s* nat_context, tnet_turn_allocation_t *allocation);
+//tnet_turn_channel_binding_id_t tnet_turn_channel_bind(const struct struct tnet_nat_ctx_s* nat_context, tnet_turn_allocation_t *allocation, struct sockaddr_storage *peer);
+//int tnet_turn_channel_refresh(const struct struct tnet_nat_ctx_s* nat_context, const tnet_turn_channel_binding_t * channel_bind);
+//int tnet_turn_channel_senddata(const struct struct tnet_nat_ctx_s* nat_context, const tnet_turn_channel_binding_t * channel_bind, const void* data, tsk_size_t size, int indication);
+//int tnet_turn_add_permission(const struct struct tnet_nat_ctx_s* nat_context, tnet_turn_allocation_t *allocation, const char* ipaddress, uint32_t timeout);
+//
+//
+//TNET_END_DECLS
+//
+//#endif /* TNET_TURN_H */
+//
diff --git a/tinyNET/src/turn/tnet_turn_attr.c b/tinyNET/src/turn/tnet_turn_attr.c
new file mode 100644
index 0000000..2303fa6
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_attr.c
@@ -0,0 +1,21 @@
+///* Copyright (C) 2014 Mamadou DIOP.
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 General Public License
+//* along with DOUBANGO.
+//*
+//*/
+//#include "turn/tnet_turn_attr.h"
+//
+//#include "tsk_debug.h" \ No newline at end of file
diff --git a/tinyNET/src/turn/tnet_turn_attr.h b/tinyNET/src/turn/tnet_turn_attr.h
new file mode 100644
index 0000000..55fb426
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_attr.h
@@ -0,0 +1,32 @@
+///* Copyright (C) 2014 Mamadou DIOP.
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 General Public License
+//* along with DOUBANGO.
+//*
+//*/
+//#ifndef TNET_TURN_ATTR_H
+//#define TNET_TURN_ATTR_H
+//
+//#include "tinynet_config.h"
+//#include "stun/tnet_stun_types.h"
+//
+//#include "tsk_object.h"
+//#include "tsk_list.h"
+//
+//TNET_BEGIN_DECLS
+//
+//TNET_END_DECLS
+//
+//#endif /* TNET_TURN_ATTR_H */
diff --git a/tinyNET/src/turn/tnet_turn_attribute.c b/tinyNET/src/turn/tnet_turn_attribute.c
new file mode 100644
index 0000000..719f926
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_attribute.c
@@ -0,0 +1,646 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_turn_attribute.c
+// * @brief New STUN Attributes as per draft-ietf-behave-turn-16 subclause 14.
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#include "tnet_turn_attribute.h"
+//
+//#include "../stun/tnet_stun.h"
+//
+//#include "../tnet_endianness.h"
+//
+//#include "tsk_debug.h"
+//
+//#include <string.h>
+//
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER */
+//tnet_turn_attribute_channelnum_t* tnet_turn_attribute_channelnum_create(uint16_t number)
+//{
+// return tsk_object_new(tnet_turn_attribute_channelnum_def_t, number);
+//}
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.2. LIFETIME */
+//tnet_turn_attribute_lifetime_t* tnet_turn_attribute_lifetime_create(uint32_t lifetime)
+//{
+// return tsk_object_new(tnet_turn_attribute_lifetime_def_t, lifetime);
+//}
+//
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS */
+//tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_turn_attribute_xpeer_addr_def_t, payload, payload_size);
+//}
+//
+//tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create_null()
+//{
+// return tnet_turn_attribute_xpeer_addr_create(tsk_null, 0);
+//}
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.4. DATA */
+//tnet_turn_attribute_data_t* tnet_turn_attribute_data_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_turn_attribute_data_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS */
+//tnet_turn_attribute_xrelayed_addr_t* tnet_turn_attribute_xrelayed_addr_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_turn_attribute_xrelayed_addr_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT */
+//tnet_turn_attribute_even_port_t* tnet_turn_attribute_even_port_create(unsigned R)
+//{
+// return tsk_object_new(tnet_turn_attribute_even_port_def_t, R);
+//}
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT */
+//tnet_turn_attribute_reqtrans_t* tnet_turn_attribute_reqtrans_create(tnet_proto_t protocol)
+//{
+// return tsk_object_new(tnet_turn_attribute_reqtrans_def_t, protocol);
+//}
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT */
+//tnet_turn_attribute_dontfrag_t* tnet_turn_attribute_dontfrag_create()
+//{
+// return tsk_object_new(tnet_turn_attribute_dontfrag_def_t);
+//}
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN */
+//tnet_turn_attribute_restoken_t* tnet_turn_attribute_restoken_create(const void* payload, tsk_size_t payload_size)
+//{
+// return tsk_object_new(tnet_turn_attribute_restoken_def_t, payload, payload_size);
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tnet_stun_attr_t* tnet_turn_attribute_deserialize(tnet_stun_attr_type_t type, uint16_t length, const void* payload, tsk_size_t payload_size)
+//{
+// tnet_stun_attr_t *attribute = tsk_null;
+// const uint8_t* dataPtr = payload;
+//
+// /* Attribute Value
+// */
+//
+// switch(type)
+// {
+// /* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER */
+// case stun_channel_number:
+// {
+// uint32_t number = tnet_htonl_2(dataPtr);
+// attribute = (tnet_stun_attr_t *)tnet_turn_attribute_channelnum_create(number);
+// break;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.2. LIFETIME */
+// case stun_lifetime:
+// {
+// uint32_t lifetime = tnet_htonl_2(dataPtr);
+// attribute = (tnet_stun_attr_t *)tnet_turn_attribute_lifetime_create(lifetime);
+// break;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS */
+// case stun_xor_peer_address:
+// {
+// TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+// break;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.4. DATA */
+// case stun_data:
+// {
+// TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+// break;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS */
+// case stun_xor_relayed_address:
+// {
+// attribute = (tnet_stun_attr_t *)tnet_turn_attribute_xrelayed_addr_create(dataPtr, length);
+// break;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT */
+// case stun_even_port:
+// {
+// TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+// break;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT */
+// case stun_requested_transport:
+// {
+// TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+// break;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT */
+// case stun_dont_fragment:
+// {
+// TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+// break;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN */
+// case stun_reservation_token:
+// {
+// TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+// break;
+// }
+//
+// default:
+// {
+// TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+// break;
+// }
+// }
+//
+// if(!attribute){
+// /* Create default */
+// attribute = tnet_stun_attribute_create();
+// }
+//
+// return attribute;
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//int tnet_turn_attribute_serialize(const tnet_stun_attr_t* attribute, tsk_buffer_t *output)
+//{
+// if(!attribute || !output){
+// return -1;
+// }
+//
+// /* Attribute Value
+// */
+//
+// switch(attribute->type){
+// /* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER */
+// case stun_channel_number:
+// {
+// tnet_turn_attribute_channelnum_t *number = (tnet_turn_attribute_channelnum_t*)attribute;
+// tsk_buffer_append(output, &(number->number), 2);
+// return 0;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.2. LIFETIME */
+// case stun_lifetime:
+// {
+// tnet_turn_attribute_lifetime_t *lifetime = (tnet_turn_attribute_lifetime_t*)attribute;
+// tsk_buffer_append(output, &(lifetime->value), 4);
+// return 0;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS */
+// case stun_xor_peer_address:
+// {
+// tnet_turn_attribute_xpeer_addr_t* xpeer = (tnet_turn_attribute_xpeer_addr_t*)attribute;
+// if(xpeer){
+// if(xpeer->family == stun_ipv4){
+// uint8_t pad = 0x00;
+// tsk_buffer_append(output, &pad, 1);
+// tsk_buffer_append(output, &xpeer->family, 1);
+// tsk_buffer_append(output, &xpeer->xport, 2);
+// tsk_buffer_append(output, xpeer->xaddress, 4);
+// }
+// else
+// {
+// TSK_DEBUG_ERROR("SERIALIZE:XOR-PEER-ADDRESS ==> IPV6 - NOT IMPLEMENTED");
+// return -3;
+// }
+// }
+// return 0;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.4. DATA */
+// case stun_data:
+// {
+// tnet_turn_attribute_data_t *data = (tnet_turn_attribute_data_t*)attribute;
+// if(data->value){
+// tsk_buffer_append(output, data->value->data, data->value->size);
+// }
+// return 0;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS */
+// case stun_xor_relayed_address:
+// {
+// TSK_DEBUG_ERROR("SERIALIZE:XOR-RELAYED-ADDRESS ==> NOT IMPLEMENTED");
+// return -3;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT */
+// case stun_even_port:
+// {
+// tnet_turn_attribute_even_port_t *even_port = (tnet_turn_attribute_even_port_t*)attribute;
+// uint8_t value = (even_port->R << 7);
+// tsk_buffer_append(output, &(value), 1);
+// return 0;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT */
+// case stun_requested_transport:
+// {
+// tnet_turn_attribute_reqtrans_t *reqtrans = (tnet_turn_attribute_reqtrans_t*)attribute;
+// tsk_buffer_append(output, &(reqtrans->protocol), 1);
+// tsk_buffer_append(output, &(reqtrans->rffu), 3);
+// return 0;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT */
+// case stun_dont_fragment:
+// {
+// TSK_DEBUG_ERROR("SERIALIZE:DONT-FRAGMENT ==> NOT IMPLEMENTED");
+// return -3;
+// }
+//
+// /* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN */
+// case stun_reservation_token:
+// {
+// TSK_DEBUG_ERROR("SERIALIZE:TOKEN ==> NOT IMPLEMENTED");
+// return -3;
+// }
+//
+// default: break;
+// }
+//
+// return 0;
+//}
+//
+//
+//
+//
+//
+//
+//
+//
+////=================================================================================================
+//// [[draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER]] object definition
+////
+//static tsk_object_t* tnet_turn_attribute_channelnum_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_attribute_channelnum_t *attribute = self;
+// if(attribute){
+// attribute->number = tsk_va_arg_u16(*app);
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_channel_number;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 2;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_attribute_channelnum_dtor(tsk_object_t * self)
+//{
+// tnet_turn_attribute_channelnum_t *attribute = self;
+// if(attribute){
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_attribute_channelnum_def_s =
+//{
+// sizeof(tnet_turn_attribute_channelnum_t),
+// tnet_turn_attribute_channelnum_ctor,
+// tnet_turn_attribute_channelnum_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_attribute_channelnum_def_t = &tnet_turn_attribute_channelnum_def_s;
+//
+//
+//
+////=================================================================================================
+//// [[draft-ietf-behave-turn-16 - 14.2. LIFETIME]] object definition
+////
+//static tsk_object_t* tnet_turn_attribute_lifetime_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_attribute_lifetime_t *attribute = self;
+// if(attribute){
+// attribute->value = /*tnet_htonl*/(va_arg(*app, uint32_t));
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_lifetime;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 4;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_attribute_lifetime_dtor(tsk_object_t * self)
+//{
+// tnet_turn_attribute_lifetime_t *attribute = self;
+// if(attribute){
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_attribute_lifetime_def_s =
+//{
+// sizeof(tnet_turn_attribute_lifetime_t),
+// tnet_turn_attribute_lifetime_ctor,
+// tnet_turn_attribute_lifetime_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_attribute_lifetime_def_t = &tnet_turn_attribute_lifetime_def_s;
+//
+//
+//
+//
+////=================================================================================================
+//// [[draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS]] object definition
+////
+//static tsk_object_t* tnet_turn_attribute_xpeer_addr_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_attribute_xpeer_addr_t *attribute = self;
+// if(attribute){
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// if(payload && payload_size){
+// }
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_xor_peer_address;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 8;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_attribute_xpeer_addr_dtor(tsk_object_t * self)
+//{
+// tnet_turn_attribute_xpeer_addr_t *attribute = self;
+// if(attribute){
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_attribute_xpeer_addr_def_s =
+//{
+// sizeof(tnet_turn_attribute_xpeer_addr_t),
+// tnet_turn_attribute_xpeer_addr_ctor,
+// tnet_turn_attribute_xpeer_addr_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_attribute_xpeer_addr_def_t = &tnet_turn_attribute_xpeer_addr_def_s;
+//
+//
+////=================================================================================================
+//// [[draft-ietf-behave-turn-16 - 14.4. DATA]] object definition
+////
+//static tsk_object_t* tnet_turn_attribute_data_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_attribute_data_t *attribute = self;
+// if(attribute){
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// if(payload && payload_size){
+// attribute->value = tsk_buffer_create(payload, payload_size);
+// }
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_data;
+// TNET_STUN_ATTRIBUTE(attribute)->length = (uint16_t)payload_size;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_attribute_data_dtor(tsk_object_t * self)
+//{
+// tnet_turn_attribute_data_t *attribute = self;
+// if(attribute){
+// TSK_OBJECT_SAFE_FREE(attribute->value);
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_attribute_data_def_s =
+//{
+// sizeof(tnet_turn_attribute_data_t),
+// tnet_turn_attribute_data_ctor,
+// tnet_turn_attribute_data_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_attribute_data_def_t = &tnet_turn_attribute_data_def_s;
+//
+////=================================================================================================
+//// [[draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS]] object definition
+////
+//static tsk_object_t* tnet_turn_attribute_xrelayed_addr_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_attribute_xrelayed_addr_t *attribute = self;
+// if(attribute){
+// const void *payload = va_arg(*app, const void*);
+// tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// if(payload && payload_size){
+// const uint8_t *payloadPtr = (const uint8_t*)payload;
+// payloadPtr += 1; /* Ignore first 8bits */
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_xor_relayed_address;
+// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+//
+// attribute->family = (tnet_stun_addr_family_t)(*(payloadPtr++));
+//
+// attribute->xport = tnet_ntohs_2(payloadPtr);
+// attribute->xport ^= 0x2112;
+// payloadPtr+=2;
+//
+// { /*=== Compute IP address */
+// tsk_size_t addr_size = (attribute->family == stun_ipv6) ? 16 : (attribute->family == stun_ipv4 ? 4 : 0);
+// if(addr_size){
+// tsk_size_t i;
+// uint32_t addr;
+//
+// for(i=0; i<addr_size; i+=4){
+// addr = tnet_htonl_2(payloadPtr);
+// addr ^= kStunMagicCookieLong;
+// memcpy(&attribute->xaddress[i], &addr, 4);
+// payloadPtr+=4;
+// }
+// }
+// else{
+// TSK_DEBUG_ERROR("UNKNOWN FAMILY [%u].", attribute->family);
+// }
+// }
+// }
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_attribute_xrelayed_addr_dtor(tsk_object_t * self)
+//{
+// tnet_turn_attribute_xrelayed_addr_t *attribute = self;
+// if(attribute){
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_attribute_xrelayed_addr_def_s =
+//{
+// sizeof(tnet_turn_attribute_xrelayed_addr_t),
+// tnet_turn_attribute_xrelayed_addr_ctor,
+// tnet_turn_attribute_xrelayed_addr_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_attribute_xrelayed_addr_def_t = &tnet_turn_attribute_xrelayed_addr_def_s;
+//
+//
+////=================================================================================================
+//// [[draft-ietf-behave-turn-16 - 14.6. EVEN-PORT]] object definition
+////
+//static tsk_object_t* tnet_turn_attribute_even_port_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_attribute_even_port_t *attribute = self;
+// if(attribute){
+// attribute->R = va_arg(*app, unsigned);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_even_port;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 1;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_attribute_even_port_dtor(tsk_object_t * self)
+//{
+// tnet_turn_attribute_even_port_t *attribute = self;
+// if(attribute){
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_attribute_even_port_def_s =
+//{
+// sizeof(tnet_turn_attribute_even_port_t),
+// tnet_turn_attribute_even_port_ctor,
+// tnet_turn_attribute_even_port_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_attribute_even_port_def_t = &tnet_turn_attribute_even_port_def_s;
+//
+//
+////=================================================================================================
+//// [[draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT]] object definition
+////
+//static tsk_object_t* tnet_turn_attribute_reqtrans_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_attribute_reqtrans_t *attribute = self;
+// if(attribute){
+// attribute->protocol = va_arg(*app, tnet_proto_t);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_requested_transport;
+// TNET_STUN_ATTRIBUTE(attribute)->length = 4;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_attribute_reqtrans_dtor(tsk_object_t * self)
+//{
+// tnet_turn_attribute_reqtrans_t *attribute = self;
+// if(attribute){
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_attribute_reqtrans_def_s =
+//{
+// sizeof(tnet_turn_attribute_reqtrans_t),
+// tnet_turn_attribute_reqtrans_ctor,
+// tnet_turn_attribute_reqtrans_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_attribute_reqtrans_def_t = &tnet_turn_attribute_reqtrans_def_s;
+//
+//
+////=================================================================================================
+//// [[draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT]] object definition
+////
+//static tsk_object_t* tnet_turn_attribute_dontfrag_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_attribute_dontfrag_t *attribute = self;
+// if(attribute){
+// //const void *payload = va_arg(*app, const void*);
+// //tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_dont_fragment;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_attribute_dontfrag_dtor(tsk_object_t * self)
+//{
+// tnet_turn_attribute_dontfrag_t *attribute = self;
+// if(attribute){
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_attribute_dontfrag_def_s =
+//{
+// sizeof(tnet_turn_attribute_dontfrag_t),
+// tnet_turn_attribute_dontfrag_ctor,
+// tnet_turn_attribute_dontfrag_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_attribute_dontfrag_def_t = &tnet_turn_attribute_dontfrag_def_s;
+//
+//
+//
+////=================================================================================================
+//// [[draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN]] object definition
+////
+//static tsk_object_t* tnet_turn_attribute_restoken_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_attribute_restoken_t *attribute = self;
+// if(attribute){
+// //--const void *payload = va_arg(*app, const void*);
+// //--tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+//
+// TNET_STUN_ATTRIBUTE(attribute)->type = stun_reservation_token;
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_attribute_restoken_dtor(tsk_object_t * self)
+//{
+// tnet_turn_attribute_restoken_t *attribute = self;
+// if(attribute){
+// }
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_attribute_restoken_def_s =
+//{
+// sizeof(tnet_turn_attribute_restoken_t),
+// tnet_turn_attribute_restoken_ctor,
+// tnet_turn_attribute_restoken_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_attribute_restoken_def_t = &tnet_turn_attribute_restoken_def_s;
diff --git a/tinyNET/src/turn/tnet_turn_attribute.h b/tinyNET/src/turn/tnet_turn_attribute.h
new file mode 100644
index 0000000..127116c
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_attribute.h
@@ -0,0 +1,196 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_turn_attribute.h
+// * @brief New STUN Attributes as per draft-ietf-behave-turn-16 subclause 14.
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#ifndef TNET_TURN_ATTRIBUTE_H
+//#define TNET_TURN_ATTRIBUTE_H
+//
+//#include "tinynet_config.h"
+//#include "tnet_proto.h"
+//#include "stun/tnet_stun_attribute.h"
+//
+//TNET_BEGIN_DECLS
+//
+//typedef tnet_stun_attr_t tnet_turn_attribute_t;
+//
+///* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Channel Number | RFFU = 0 |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//*/
+///**@ingroup tnet_turn_group
+//*/
+//typedef struct tnet_turn_attribute_channelnum_s
+//{
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// uint16_t number;
+// uint16_t rffu;
+//}
+//tnet_turn_attribute_channelnum_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_channelnum_def_t;
+//
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.2. LIFETIME
+//*/
+//typedef struct tnet_turn_attribute_lifetime_s
+//{
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// uint32_t value;
+//}
+//tnet_turn_attribute_lifetime_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_lifetime_def_t;
+//
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS
+//*/
+//typedef struct tnet_turn_attribute_xpeer_addr_s
+//{
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// tnet_stun_addr_family_t family;
+// uint16_t xport;
+// uint8_t xaddress[16];
+//}
+//tnet_turn_attribute_xpeer_addr_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_xpeer_addr_def_t;
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.4. DATA
+//*/
+//typedef struct tnet_turn_attribute_data_s
+//{
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// tsk_buffer_t* value;
+//}
+//tnet_turn_attribute_data_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_data_def_t;
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS
+//*/
+//typedef struct tnet_turn_attribute_xrelayed_addr_s
+//{
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// tnet_stun_addr_family_t family;
+// uint16_t xport;
+// uint8_t xaddress[16];
+//}
+//tnet_turn_attribute_xrelayed_addr_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_xrelayed_addr_def_t;
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT
+//*/
+//typedef struct tnet_turn_attribute_even_port_s
+//{
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+///*
+// 0 1 2 3 4 5 6 7
+// +-+-+-+-+-+-+-+-+
+// |R| RFFU |
+// +-+-+-+-+-+-+-+-+
+//*/
+// unsigned R:1;
+// unsigned rffu:7;
+//}
+//tnet_turn_attribute_even_port_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_even_port_def_t;
+//
+//
+///**@ingroup tnet_turn_group
+//*/
+//typedef struct tnet_turn_attribute_reqtrans_s
+//{
+// TNET_STUN_DECLARE_ATTRIBUTE;
+///*
+// draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Protocol | RFFU |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//*/
+// tnet_proto_t protocol;
+// uint8_t rffu[3];
+//}
+//tnet_turn_attribute_reqtrans_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_reqtrans_def_t;
+//
+//
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT
+//*/
+//typedef struct tnet_turn_attribute_dontfrag_s
+//{
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//}
+//tnet_turn_attribute_dontfrag_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_dontfrag_def_t;
+//
+//
+///**@ingroup tnet_turn_group
+//* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN
+//*/
+//typedef struct tnet_turn_attribute_restoken_s
+//{
+// TNET_STUN_DECLARE_ATTRIBUTE;
+//
+// uint8_t value[8];
+//}
+//tnet_turn_attribute_restoken_t;
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_restoken_def_t;
+//
+//
+//tnet_stun_attr_t* tnet_turn_attribute_deserialize(tnet_stun_attr_type_t type, uint16_t length, const void* payload, tsk_size_t payload_size);
+//int tnet_turn_attribute_serialize(const tnet_stun_attr_t* attribute, tsk_buffer_t *output);
+//
+//tnet_turn_attribute_channelnum_t* tnet_turn_attribute_channelnum_create(uint16_t number);
+//tnet_turn_attribute_lifetime_t* tnet_turn_attribute_lifetime_create(uint32_t lifetime);
+//tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create(const void* payload, tsk_size_t payload_size);
+//tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create_null();
+//tnet_turn_attribute_data_t* tnet_turn_attribute_data_create(const void* payload, tsk_size_t payload_size);
+//tnet_turn_attribute_xrelayed_addr_t* tnet_turn_attribute_xrelayed_addr_create(const void* payload, tsk_size_t payload_size);
+//tnet_turn_attribute_even_port_t* tnet_turn_attribute_even_port_create(unsigned R);
+//tnet_turn_attribute_reqtrans_t* tnet_turn_attribute_reqtrans_create(tnet_proto_t protocol);
+//tnet_turn_attribute_dontfrag_t* tnet_turn_attribute_dontfrag_create();
+//tnet_turn_attribute_restoken_t* tnet_turn_attribute_restoken_create(const void* payload, tsk_size_t payload_size);
+//
+//TNET_END_DECLS
+//
+//#endif /* TNET_TURN_ATTRIBUTE_H */
+//
diff --git a/tinyNET/src/turn/tnet_turn_message.c b/tinyNET/src/turn/tnet_turn_message.c
new file mode 100644
index 0000000..989fd2b
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_message.c
@@ -0,0 +1,163 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_turn_message.c
+// * @brief Traversal Using Relays around NAT (TURN) messages.
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#include "tnet_turn_message.h"
+//
+//#include "../tnet_types.h"
+//#include "../tnet_endianness.h"
+//
+//#include "tsk_memory.h"
+//
+//#include <string.h>
+//
+//tnet_turn_channel_data_t* tnet_turn_channel_data_create(uint16_t number, uint16_t length, const void* data)
+//{
+// return tsk_object_new(tnet_turn_channel_data_def_t, number, length, data);
+//}
+//
+//tnet_turn_channel_data_t* tnet_turn_channel_data_create_null()
+//{
+// return tnet_turn_channel_data_create(0, 0, tsk_null);
+//}
+//
+///**@ingroup tnet_turn_group
+//*/
+//tsk_buffer_t* tnet_turn_channel_data_serialize(const tnet_turn_channel_data_t *message)
+//{
+// tsk_buffer_t *output = 0;
+//
+// if(!message) goto bail;
+//
+// output = tsk_buffer_create_null();
+//
+// /* draft-ietf-behave-turn-16 11.4. The ChannelData Message
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Channel Number | Length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// / Application Data /
+// / /
+// | |
+// | +-------------------------------+
+// | |
+// +-------------------------------+
+// */
+//
+// /* Channel Number
+// */
+// {
+// uint16_t number = tnet_htons(message->chanel_number);
+// tsk_buffer_append(output, &(number), 2);
+// }
+//
+// /* Length
+// */
+// {
+// uint16_t length = tnet_htons(message->length);
+// tsk_buffer_append(output, &(length), 2);
+// }
+//
+// /* Application Data
+// */
+// {
+// tsk_buffer_append(output, message->data, message->length);
+//
+// /* === Padding:
+// Over stream transports, the ChannelData message MUST be padded to a
+// multiple of four bytes in order to ensure the alignment of subsequent
+// messages. The padding is not reflected in the length field of the
+// ChannelData message, so the actual size of a ChannelData message
+// (including padding) is (4 + Length) rounded up to the nearest
+// multiple of 4. Over UDP, the padding is not required but MAY be included.
+// */
+// if(message->length%4)
+// {
+// static uint32_t zeros = 0x00000000;
+// tsk_buffer_append(output, &zeros, 4-(message->length%4));
+// }
+// }
+//
+//bail:
+// return output;
+//}
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+////=================================================================================================
+//// TURN CHANNEL-DATA message object definition
+////
+//static tsk_object_t* tnet_turn_channel_data_ctor(tsk_object_t * self, va_list * app)
+//{
+// tnet_turn_channel_data_t *message = self;
+// if(message){
+// const void* data;
+// message->chanel_number = tsk_va_arg_u16(*app);
+// message->length = tsk_va_arg_u16(*app);
+// data = va_arg(*app, const void*);
+// if(data && message->length){
+// if((message->data = tsk_calloc(message->length, sizeof(uint8_t)))){
+// memcpy(message->data, data, message->length);
+// }
+// }
+// }
+// return self;
+//}
+//
+//static tsk_object_t* tnet_turn_channel_data_dtor(tsk_object_t * self)
+//{
+// tnet_turn_channel_data_t *message = self;
+// if(message){
+// TSK_FREE(message->data);
+// }
+//
+// return self;
+//}
+//
+//static const tsk_object_def_t tnet_turn_channel_data_def_s =
+//{
+// sizeof(tnet_turn_channel_data_t),
+// tnet_turn_channel_data_ctor,
+// tnet_turn_channel_data_dtor,
+// tsk_null,
+//};
+//const tsk_object_def_t *tnet_turn_channel_data_def_t = &tnet_turn_channel_data_def_s;
diff --git a/tinyNET/src/turn/tnet_turn_message.h b/tinyNET/src/turn/tnet_turn_message.h
new file mode 100644
index 0000000..c518366
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_message.h
@@ -0,0 +1,75 @@
+///*
+//* Copyright (C) 2010-2011 Mamadou Diop.
+//*
+//* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
+//*
+//* This file is part of Open Source Doubango Framework.
+//*
+//* DOUBANGO 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 3 of the License, or
+//* (at your option) any later version.
+//*
+//* DOUBANGO 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 DOUBANGO.
+//*
+//*/
+//
+///**@file tnet_turn_message.h
+// * @brief Traversal Using Relays around NAT (TURN) messages.
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+// *
+//
+// */
+//#ifndef TNET_TURN_MESSAGE_H
+//#define TNET_TURN_MESSAGE_H
+//
+//#include "../tinynet_config.h"
+//
+//#include "tsk_buffer.h"
+//
+//TNET_BEGIN_DECLS
+//
+///**@ingroup tnet_turn_group
+// * TURN channel data message as per draft-ietf-behave-turn-16 subclause 11.4.
+//*/
+//typedef struct tnet_turn_channel_data_s
+//{
+// TSK_DECLARE_OBJECT;
+//
+// /* draft-ietf-behave-turn-16 11.4. The ChannelData Message
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Channel Number | Length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// / Application Data /
+// / /
+// | |
+// | +-------------------------------+
+// | |
+// +-------------------------------+
+// */
+// uint16_t chanel_number;
+// uint16_t length;
+// void* data;
+//}
+//tnet_turn_channel_data_t;
+//
+//tsk_buffer_t* tnet_turn_channel_data_serialize(const tnet_turn_channel_data_t *message);
+//
+//tnet_turn_channel_data_t* tnet_turn_channel_data_create(uint16_t number, uint16_t length, const void* data);
+//tnet_turn_channel_data_t* tnet_turn_channel_data_create_null();
+//
+//TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_channel_data_def_t;
+//
+//TNET_END_DECLS
+//
+//#endif /* TNET_TURN_MESSAGE_H */
diff --git a/tinyNET/src/turn/tnet_turn_session.c b/tinyNET/src/turn/tnet_turn_session.c
new file mode 100644
index 0000000..e131dbc
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_session.c
@@ -0,0 +1,2487 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#include "turn/tnet_turn_session.h"
+
+#include "stun/tnet_stun_pkt.h"
+#include "stun/tnet_stun_utils.h"
+
+#include "tinynet.h"
+#include "tnet_proxydetect.h"
+
+#include "tsk_string.h"
+#include "tsk_timer.h"
+#include "tsk_time.h"
+#include "tsk_safeobj.h"
+#include "tsk_debug.h"
+
+#define kTurnTransportFriendlyName "TURN transport"
+#define kTurnTransportConnectTimeout 1500 // 1.5sec to wait until socket get connected
+#define kTurnStreamChunckMaxSize 0xFFFF // max size of a chunck to form a valid STUN message. Used as a guard.
+#define kTurnStreamOutMaxSize 0xFFFF // max pending data size
+
+#define TNET_TURN_SESSION_TIMOUT_GET_BEST_SEC(u_timeout_in_sec) ((u_timeout_in_sec)*950) // add small delay for code execution
+#define TNET_TURN_SESSION_TIMOUT_GET_BEST_MILLIS(u_timeout_in_millis) (((u_timeout_in_millis)*950)/1000) // add small delay for code execution
+
+#define TNET_TURN_SESSION_TIMER_SCHEDULE_SEC(_p_self, u_id, u_timeout_in_sec) \
+ (u_id) = tsk_timer_manager_schedule((_p_self)->timer.p_mgr, TNET_TURN_SESSION_TIMOUT_GET_BEST_SEC((u_timeout_in_sec)), _tnet_turn_session_timer_callback, (_p_self))
+#define TNET_TURN_SESSION_TIMER_SCHEDULE_MILLIS(_p_self, u_id, u_timeout_in_millis) \
+ (u_id) = tsk_timer_manager_schedule((_p_self)->timer.p_mgr, TNET_TURN_SESSION_TIMOUT_GET_BEST_MILLIS((u_timeout_in_millis)), _tnet_turn_session_timer_callback, (_p_self))
+
+typedef tnet_stun_pkt_t tnet_turn_pkt_t;
+
+typedef struct tnet_turn_peer_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_turn_peer_id_t id;
+
+ uint16_t u_chan_num;
+ uint32_t u_conn_id; // rfc6062 - 6.2.1. CONNECTION-ID, For streams only
+ tnet_fd_t conn_fd; // Connected FD: used for Streams only
+
+ tnet_stun_addr_t addr_ip;
+ char* p_addr_ip;
+ uint16_t u_addr_port;
+ tsk_bool_t b_ipv6;
+ tsk_bool_t b_stream_connected;
+ tsk_buffer_t *p_stream_buff_in;
+ tsk_buffer_t *p_stream_buff_out;
+
+ tnet_stun_state_t e_createperm_state;
+ tnet_stun_state_t e_chanbind_state;
+ tnet_stun_state_t e_connect_state;
+ tnet_stun_state_t e_connbind_state;
+
+ tnet_turn_pkt_t* p_pkt_createperm;
+ tnet_stun_pkt_t* p_pkt_sendind;
+ tnet_stun_pkt_t* p_pkt_chanbind;
+ tnet_stun_pkt_t* p_pkt_connect; // For streams only
+ tnet_stun_pkt_t* p_pkt_connbind; // For streams only
+
+ struct {
+ struct {
+ struct {
+ tsk_timer_id_t id;
+ uint64_t u_timeout;
+ } createperm;
+ struct {
+ tsk_timer_id_t id;
+ uint64_t u_timeout;
+ } chanbind;
+ } fresh; // schedule refresh
+ struct {
+ struct {
+ tsk_timer_id_t id;
+ uint64_t u_timeout;
+ } createperm;
+ struct {
+ tsk_timer_id_t id;
+ uint64_t u_timeout;
+ } chanbind;
+ } rtt; // retransmit (UDP only, to deal with pkt loss)
+ } timer;
+}
+tnet_turn_peer_t;
+typedef tsk_list_t tnet_turn_peers_L_t;
+
+typedef struct tnet_turn_session_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_bool_t b_prepared;
+ tsk_bool_t b_started;
+ tsk_bool_t b_stopping;
+ enum tnet_stun_state_e e_alloc_state;
+ enum tnet_stun_state_e e_refresh_state;
+
+ enum tnet_turn_transport_e e_req_transport;
+
+ uint32_t u_lifetime_alloc_in_sec;
+
+ tnet_turn_pkt_t* p_pkt_alloc;
+ tnet_stun_pkt_t* p_pkt_refresh;
+
+ void* p_buff_send_ptr;
+ tsk_size_t u_buff_send_size;
+
+ void* p_buff_chandata_ptr;
+ tsk_size_t u_buff_chandata_size;
+
+ char* p_rel_ip;
+ uint16_t u_rel_port;
+ tsk_bool_t b_rel_ipv6;
+
+ char* p_srflx_ip;
+ uint16_t u_srflx_port;
+ tsk_bool_t b_srflx_ipv6;
+
+ struct {
+ tsk_bool_t auto_detect;
+ struct tnet_proxyinfo_s* info;
+ }
+ proxy;
+
+ struct {
+ char* path_priv;
+ char* path_pub;
+ char* path_ca;
+ tsk_bool_t verify;
+ } ssl;
+
+ struct {
+ char* p_usr_name;
+ char* p_pwd;
+ } cred;
+
+ struct {
+ tnet_turn_session_callback_f f_fun;
+ struct tnet_turn_session_event_xs e;
+ } cb;
+
+ struct {
+ tsk_timer_manager_handle_t *p_mgr;
+ tsk_timer_id_t u_timer_id_refresh; // To refresh Alloc (Send Refresh Indication)
+ struct {
+ struct {
+ tsk_timer_id_t id;
+ uint64_t u_timeout;
+ } alloc;
+ struct {
+ tsk_timer_id_t id;
+ uint64_t u_timeout;
+ } refresh;
+ } rtt; // retransmit (UDP only)
+ } timer;
+
+ tnet_socket_t* p_lcl_sock;
+ char* p_srv_host;
+ uint16_t u_srv_port;
+ tsk_bool_t b_stream_connected;
+ tsk_buffer_t* p_stream_buff_out; // data pending until the socket is connected
+ tsk_bool_t b_stream_error; // Unrecoverable error occured
+ tsk_buffer_t *p_stream_buff_in;
+ struct sockaddr_storage srv_addr;
+ struct tnet_transport_s* p_transport;
+
+ tnet_turn_peers_L_t* p_list_peers;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_turn_session_t;
+
+static uint16_t _tnet_turn_session_get_unique_chan_num();
+static int _tnet_turn_session_send_chandata(tnet_turn_session_t* p_self, const tnet_turn_peer_t* pc_peer, const void* pc_buff_ptr, tsk_size_t u_buff_size);
+static int _tnet_turn_session_send_stream_raw(tnet_turn_session_t* p_self, tnet_turn_peer_t* pc_peer, const void* pc_buff_ptr, tsk_size_t u_buff_size);
+static int _tnet_turn_session_send_refresh(tnet_turn_session_t* p_self);
+static int _tnet_turn_session_send_permission(struct tnet_turn_session_s* p_self, tnet_turn_peer_t *p_peer);
+static int _tnet_turn_session_send_connbind(struct tnet_turn_session_s* p_self, tnet_turn_peer_t *p_peer);
+static int _tnet_turn_session_send_buff_0(tnet_turn_session_t* p_self, const tnet_turn_peer_t* pc_peer, const void* pc_buff_ptr, tsk_size_t u_buff_size);
+static int _tnet_turn_session_send_buff(tnet_turn_session_t* p_self, const void* pc_buff_ptr, tsk_size_t u_buff_size);
+static int _tnet_turn_session_send_pkt_0(tnet_turn_session_t* p_self, const tnet_turn_peer_t* pc_peer, const tnet_turn_pkt_t *pc_pkt);
+static int _tnet_turn_session_send_pkt(tnet_turn_session_t* p_self, const tnet_turn_pkt_t *pc_pkt);
+static int _tnet_turn_session_process_incoming_pkt(struct tnet_turn_session_s* p_self, const tnet_turn_pkt_t *pc_pkt, tsk_bool_t *pb_processed);
+static int _tnet_turn_session_process_success_connect_pkt(struct tnet_turn_session_s* p_self, tnet_turn_peer_t* pc_peer, const tnet_turn_pkt_t *pc_pkt);
+static int _tnet_turn_session_process_err420_pkt(tnet_turn_pkt_t *p_pkt_req, const tnet_turn_pkt_t *pc_pkt_resp420);
+static int _tnet_turn_session_transport_layer_dgram_cb(const tnet_transport_event_t* e);
+static int _tnet_turn_session_transport_layer_stream_cb(const tnet_transport_event_t* e);
+static int _tnet_turn_session_transport_layer_process_cb(const tnet_transport_event_t* e);
+static int _tnet_turn_session_timer_callback(const void* pc_arg, tsk_timer_id_t timer_id);
+
+static int _tnet_turn_peer_create(const char* pc_peer_ip, uint16_t u_peer_port, tsk_bool_t b_ipv6, struct tnet_turn_peer_s **pp_peer);
+static int _tnet_turn_peer_find_by_xpeer(const tnet_turn_peers_L_t* pc_peers, const tnet_stun_attr_address_t* pc_xpeer, const tnet_turn_peer_t **ppc_peer);
+
+/*** PREDICATES ***/
+static int __pred_find_peer_by_id(const tsk_list_item_t *item, const void *id) {
+ if (item && item->data) {
+ return (int)(((const struct tnet_turn_peer_s *)item->data)->id - *((const tnet_turn_peer_id_t*)id));
+ }
+ return -1;
+}
+static int __pred_find_peer_by_fd(const tsk_list_item_t *item, const void *fd) {
+ if (item && item->data) {
+ return (int)(((const struct tnet_turn_peer_s *)item->data)->conn_fd - *((const tnet_fd_t*)fd));
+ }
+ return -1;
+}
+static int __pred_find_peer_by_channum(const tsk_list_item_t *item, const void *pu_chan_num) {
+ if (item && item->data) {
+ return (int)(((const struct tnet_turn_peer_s *)item->data)->u_chan_num - *((const uint16_t*)pu_chan_num));
+ }
+ return -1;
+}
+static int __pred_find_peer_by_timer_rtt_createperm(const tsk_list_item_t *item, const void *id) {
+ if (item && item->data) {
+ return (int)(((const struct tnet_turn_peer_s *)item->data)->timer.rtt.createperm.id - *((const tsk_timer_id_t*)id));
+ }
+ return -1;
+}
+static int __pred_find_peer_by_timer_fresh_createperm(const tsk_list_item_t *item, const void *id) {
+ if (item && item->data) {
+ return (int)(((const struct tnet_turn_peer_s *)item->data)->timer.fresh.createperm.id - *((const tsk_timer_id_t*)id));
+ }
+ return -1;
+}
+static int __pred_find_peer_by_transacid_createperm(const tsk_list_item_t *item, const void *pc_transacid) {
+ if (item && item->data) {
+ return ((const struct tnet_turn_peer_s *)item->data)->p_pkt_createperm
+ ? tnet_stun_utils_transac_id_cmp(((const struct tnet_turn_peer_s *)item->data)->p_pkt_createperm->transac_id, *((const tnet_stun_transac_id_t*)pc_transacid))
+ : +1;
+ }
+ return -1;
+}
+static int __pred_find_peer_by_timer_rtt_chanbind(const tsk_list_item_t *item, const void *id) {
+ if (item && item->data) {
+ return (int)(((const struct tnet_turn_peer_s *)item->data)->timer.rtt.chanbind.id - *((const tsk_timer_id_t*)id));
+ }
+ return -1;
+}
+static int __pred_find_peer_by_timer_fresh_chanbind(const tsk_list_item_t *item, const void *id) {
+ if (item && item->data) {
+ return (int)(((const struct tnet_turn_peer_s *)item->data)->timer.fresh.chanbind.id - *((const tsk_timer_id_t*)id));
+ }
+ return -1;
+}
+static int __pred_find_peer_by_transacid_chanbind(const tsk_list_item_t *item, const void *pc_transacid) {
+ if (item && item->data) {
+ return ((const struct tnet_turn_peer_s *)item->data)->p_pkt_chanbind
+ ? tnet_stun_utils_transac_id_cmp(((const struct tnet_turn_peer_s *)item->data)->p_pkt_chanbind->transac_id, *((const tnet_stun_transac_id_t*)pc_transacid))
+ : +1;
+ }
+ return -1;
+}
+static int __pred_find_peer_by_transacid_connect(const tsk_list_item_t *item, const void *pc_transacid) {
+ if (item && item->data) {
+ return ((const struct tnet_turn_peer_s *)item->data)->p_pkt_connect
+ ? tnet_stun_utils_transac_id_cmp(((const struct tnet_turn_peer_s *)item->data)->p_pkt_connect->transac_id, *((const tnet_stun_transac_id_t*)pc_transacid))
+ : +1;
+ }
+ return -1;
+}
+static int __pred_find_peer_by_transacid_connectionbind(const tsk_list_item_t *item, const void *pc_transacid) {
+ if (item && item->data) {
+ return ((const struct tnet_turn_peer_s *)item->data)->p_pkt_connbind
+ ? tnet_stun_utils_transac_id_cmp(((const struct tnet_turn_peer_s *)item->data)->p_pkt_connbind->transac_id, *((const tnet_stun_transac_id_t*)pc_transacid))
+ : +1;
+ }
+ return -1;
+}
+static int __pred_find_peer_by_transacid_sendind(const tsk_list_item_t *item, const void *pc_transacid) {
+ if (item && item->data) {
+ return ((const struct tnet_turn_peer_s *)item->data)->p_pkt_sendind
+ ? tnet_stun_utils_transac_id_cmp(((const struct tnet_turn_peer_s *)item->data)->p_pkt_sendind->transac_id, *((const tnet_stun_transac_id_t*)pc_transacid))
+ : +1;
+ }
+ return -1;
+}
+
+#define _tnet_turn_session_raise_event0(_p_self, _e_type, _u_peer_id) \
+ if ((_p_self)->cb.f_fun) { \
+ (_p_self)->cb.e.e_type = _e_type; \
+ (_p_self)->cb.e.u_peer_id = _u_peer_id; \
+ (_p_self)->cb.f_fun(&(_p_self)->cb.e); \
+ }
+#define _tnet_turn_session_raise_event1(_p_self, _e_type, _u_peer_id, _pc_data_ptr, _u_data_size) \
+ if ((_p_self)->cb.f_fun) { \
+ (_p_self)->cb.e.e_type = _e_type; \
+ (_p_self)->cb.e.u_peer_id = _u_peer_id; \
+ (_p_self)->cb.e.data.pc_data_ptr = _pc_data_ptr; \
+ (_p_self)->cb.e.data.u_data_size = _u_data_size; \
+ (_p_self)->cb.f_fun(&(_p_self)->cb.e); \
+ }
+#define _tnet_turn_session_raise_event_alloc_ok(p_self) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_alloc_ok, kTurnPeerIdInvalid)
+#define _tnet_turn_session_raise_event_alloc_nok(p_self) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_alloc_nok, kTurnPeerIdInvalid)
+#define _tnet_turn_session_raise_event_refresh_ok(p_self) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_refresh_ok, kTurnPeerIdInvalid)
+#define _tnet_turn_session_raise_event_refresh_nok(p_self) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_refresh_nok, kTurnPeerIdInvalid)
+#define _tnet_turn_session_raise_event_createperm_ok(p_self, u_peer_id) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_perm_ok, (u_peer_id))
+#define _tnet_turn_session_raise_event_createperm_nok(p_self, u_peer_id) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_perm_nok, (u_peer_id))
+#define _tnet_turn_session_raise_event_chanbind_ok(p_self, u_peer_id) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_chanbind_ok, (u_peer_id))
+#define _tnet_turn_session_raise_event_chanbind_nok(p_self, u_peer_id) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_chanbind_nok, (u_peer_id))
+#define _tnet_turn_session_raise_event_connect_ok(p_self, u_peer_id) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_connect_ok, (u_peer_id))
+#define _tnet_turn_session_raise_event_connect_nok(p_self, u_peer_id) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_connect_nok, (u_peer_id))
+#define _tnet_turn_session_raise_event_connectionbind_ok(p_self, u_peer_id) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_connectionbind_ok, (u_peer_id))
+#define _tnet_turn_session_raise_event_connectionbind_nok(p_self, u_peer_id) _tnet_turn_session_raise_event0((p_self), tnet_turn_session_event_type_connectionbind_nok, (u_peer_id))
+#define _tnet_turn_session_raise_event_recv_data(p_self, u_peer_id, pc_data_ptr, u_data_size) _tnet_turn_session_raise_event1((p_self), tnet_turn_session_event_type_recv_data, (u_peer_id), (pc_data_ptr), (u_data_size))
+
+
+int tnet_turn_session_create(struct tnet_socket_s* p_lcl_sock, enum tnet_turn_transport_e e_req_transport, const char* pc_srv_host, uint16_t u_srv_port, struct tnet_turn_session_s** pp_self)
+{
+ int ret;
+ extern const tsk_object_def_t *tnet_turn_session_def_t;
+ tnet_turn_session_t* p_self;
+ if (!p_lcl_sock || !TNET_SOCKET_IS_VALID(p_lcl_sock) || !pc_srv_host || !u_srv_port || !pp_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!(p_self = tsk_object_new(tnet_turn_session_def_t))) {
+ TSK_DEBUG_ERROR("Failed to create 'tnet_turn_session_def_t' object");
+ return -2;
+ }
+ if (!(p_self->p_list_peers = tsk_list_create())) {
+ TSK_DEBUG_ERROR("Failed to create list");
+ ret = -3;
+ goto bail;
+ }
+ if (TNET_SOCKET_TYPE_IS_STREAM(p_lcl_sock->type) && !(p_self->p_stream_buff_in = tsk_buffer_create_null())) {
+ TSK_DEBUG_ERROR("Failed to stream buffer");
+ ret = -4;
+ goto bail;
+ }
+ if ((ret = tnet_sockaddr_init(pc_srv_host, u_srv_port, p_lcl_sock->type, &p_self->srv_addr))) {
+ TSK_DEBUG_ERROR("Invalid TURN SRV address [%s:%u]", pc_srv_host, u_srv_port);
+ goto bail;
+ }
+ tsk_strupdate(&p_self->p_srv_host, pc_srv_host);
+ p_self->u_srv_port = u_srv_port;
+ p_self->p_lcl_sock = tsk_object_ref(p_lcl_sock);
+ p_self->e_req_transport = e_req_transport;
+ p_self->cb.e.pc_session = p_self;
+ *pp_self = p_self;
+bail:
+ if (ret) {
+ TSK_OBJECT_SAFE_FREE(p_self);
+ }
+ return ret;
+}
+
+int tnet_turn_session_create_2(const char* pc_lcl_ip, uint16_t u_lcl_port, enum tnet_socket_type_e e_lcl_type, enum tnet_turn_transport_e e_req_transport, const char* pc_srv_host, uint16_t u_srv_port, struct tnet_turn_session_s** pp_self)
+{
+ tnet_socket_t* p_lcl_sock;
+ int ret;
+ if (!pc_srv_host || !u_srv_port || !pp_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(!(p_lcl_sock = tnet_socket_create(pc_lcl_ip, u_lcl_port, e_lcl_type))) {
+ TSK_DEBUG_ERROR("Failed to create socket(%s:%u$%d)", pc_lcl_ip, u_lcl_port, e_lcl_type);
+ return -2;
+ }
+ ret = tnet_turn_session_create(p_lcl_sock, e_req_transport, pc_srv_host, u_srv_port, pp_self);
+ TSK_OBJECT_SAFE_FREE(p_lcl_sock);
+ return ret;
+}
+
+int tnet_turn_session_create_4(struct tnet_socket_s* p_lcl_sock, enum tnet_turn_transport_e e_req_transport, const char* pc_srv_host, uint16_t u_srv_port, enum tnet_socket_type_e e_srv_type, struct tnet_turn_session_s** pp_self)
+{
+ struct tnet_socket_s* _p_lcl_sock;
+ int ret;
+
+ if (TNET_SOCKET_TYPE_IS_STREAM(e_srv_type)) {
+ // For stream the socket will be connected to the server and this is why we need to create a new socket
+ if (!(_p_lcl_sock = tnet_socket_create(p_lcl_sock->ip, TNET_SOCKET_PORT_ANY/*p_lcl_sock->port*/, e_srv_type))) {
+ return -2;
+ }
+ }
+ else {
+ // For UDP, use the socket socket
+ _p_lcl_sock = tsk_object_ref(p_lcl_sock);
+ }
+ ret = tnet_turn_session_create(_p_lcl_sock, e_req_transport, pc_srv_host, u_srv_port, pp_self);
+ TSK_OBJECT_SAFE_FREE(_p_lcl_sock);
+ return ret;
+}
+
+int tnet_turn_session_set_cred(tnet_turn_session_t* p_self, const char* pc_usr_name, const char* pc_pwd)
+{
+ if (!p_self || !pc_usr_name || !pc_pwd) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_strupdate(&p_self->cred.p_usr_name, pc_usr_name);
+ tsk_strupdate(&p_self->cred.p_pwd, pc_pwd);
+
+ return 0;
+}
+
+int tnet_turn_session_set_callback(struct tnet_turn_session_s* p_self, tnet_turn_session_callback_f f_fun, const void* pc_usr_data)
+{
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ p_self->cb.f_fun = f_fun;
+ p_self->cb.e.pc_usr_data = pc_usr_data;
+ return 0;
+}
+
+int tnet_turn_session_set_ssl_certs(struct tnet_turn_session_s* p_self, const char* path_priv, const char* path_pub, const char* path_ca, tsk_bool_t verify)
+{
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(p_self);
+ tsk_strupdate(&p_self->ssl.path_priv, path_priv);
+ tsk_strupdate(&p_self->ssl.path_pub, path_pub);
+ tsk_strupdate(&p_self->ssl.path_ca, path_ca);
+ p_self->ssl.verify = verify;
+ tsk_safeobj_unlock(p_self);
+ return 0;
+}
+
+int tnet_turn_session_set_proxy_auto_detect(struct tnet_turn_session_s* p_self, tsk_bool_t auto_detect)
+{
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(p_self);
+ p_self->proxy.auto_detect = auto_detect;
+ tsk_safeobj_unlock(p_self);
+ return 0;
+}
+
+int tnet_turn_session_set_proxy_info(struct tnet_turn_session_s* p_self, struct tnet_proxyinfo_s* info)
+{
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(p_self);
+ TSK_OBJECT_SAFE_FREE(p_self->proxy.info);
+ p_self->proxy.info = tsk_object_ref(info);
+ tsk_safeobj_unlock(p_self);
+ return 0;
+}
+
+int tnet_turn_session_prepare(tnet_turn_session_t* p_self)
+{
+ int ret = 0;
+
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (p_self->b_prepared) {
+ goto bail;
+ }
+
+ p_self->e_alloc_state = tnet_stun_state_none;
+ p_self->e_refresh_state = tnet_stun_state_none;
+
+ p_self->timer.rtt.alloc.id = TSK_INVALID_TIMER_ID;
+ p_self->timer.rtt.refresh.id = TSK_INVALID_TIMER_ID;
+
+ p_self->timer.u_timer_id_refresh = TSK_INVALID_TIMER_ID;
+ p_self->u_lifetime_alloc_in_sec = kTurnAllocationTimeOutInSec;
+
+ TSK_OBJECT_SAFE_FREE(p_self->p_pkt_alloc);
+ TSK_OBJECT_SAFE_FREE(p_self->p_pkt_refresh);
+
+ // create timer manager
+ if (!p_self->timer.p_mgr && !(p_self->timer.p_mgr = tsk_timer_manager_create())) {
+ TSK_DEBUG_ERROR("Failed to create timer manager");
+ ret = -4;
+ goto bail;
+ }
+
+ // create transport
+ if (!p_self->p_transport) {
+ if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->p_lcl_sock->type)) {
+ // Use the DGram socket as master
+ p_self->p_transport = tnet_transport_create_2(p_self->p_lcl_sock, kTurnTransportFriendlyName);
+ }
+ else {
+ // Use the Stream socket later and connect it
+ p_self->p_transport = tnet_transport_create(p_self->p_lcl_sock->ip, TNET_SOCKET_PORT_ANY, p_self->p_lcl_sock->type, kTurnTransportFriendlyName);
+ }
+ if (!p_self->p_transport) {
+ TSK_DEBUG_ERROR("Failed to create %s Transport", kTurnTransportFriendlyName);
+ ret = -5;
+ goto bail;
+ }
+ }
+ // set transport callback
+ if ((ret = tnet_transport_set_callback(p_self->p_transport, TNET_SOCKET_TYPE_IS_DGRAM(p_self->p_lcl_sock->type) ? _tnet_turn_session_transport_layer_dgram_cb : _tnet_turn_session_transport_layer_stream_cb, p_self))) {
+ goto bail;
+ }
+
+ p_self->b_prepared = tsk_true;
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+int tnet_turn_session_start(tnet_turn_session_t* p_self)
+{
+ int ret = 0;
+
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (p_self->b_started) {
+ goto bail;
+ }
+ if (!p_self->b_prepared) {
+ TSK_DEBUG_ERROR("TURN session not prepared yet");
+ ret = -2;
+ goto bail;
+ }
+
+ // start timer manager
+ if ((ret = tsk_timer_manager_start(p_self->timer.p_mgr))) {
+ TSK_DEBUG_ERROR("Failed to start TURN timer manager");
+ goto bail;
+ }
+
+ // set SSL certificates
+ if (TNET_SOCKET_TYPE_IS_TLS(p_self->p_lcl_sock->type) || TNET_SOCKET_TYPE_IS_WSS(p_self->p_lcl_sock->type)) {
+ if ((ret = tnet_transport_tls_set_certs(p_self->p_transport, p_self->ssl.path_ca, p_self->ssl.path_pub, p_self->ssl.path_priv, p_self->ssl.verify))) {
+ TSK_DEBUG_ERROR("Failed to set SSL certificates: '%s', '%s', '%s'", p_self->ssl.path_ca, p_self->ssl.path_pub, p_self->ssl.path_priv);
+ goto bail;
+ }
+ }
+
+ // Proxy info
+ if ((ret = tnet_transport_set_proxy_auto_detect(p_self->p_transport, p_self->proxy.auto_detect))) {
+ TSK_DEBUG_ERROR("Failed to set proxy autodetect option");
+ goto bail;
+ }
+ if (p_self->proxy.info) {
+ if ((ret = tnet_transport_set_proxy_info(p_self->p_transport, p_self->proxy.info->type, p_self->proxy.info->hostname, p_self->proxy.info->port, p_self->proxy.info->username, p_self->proxy.info->password))) {
+ TSK_DEBUG_ERROR("Failed to set proxy info");
+ goto bail;
+ }
+ }
+
+ // start network transport
+ if ((ret = tnet_transport_start(p_self->p_transport))) {
+ TSK_DEBUG_ERROR("Failed to start TURN transport");
+ goto bail;
+ }
+
+ // Connect to the server
+ if (TNET_SOCKET_TYPE_IS_STREAM(p_self->p_lcl_sock->type)) {
+ tnet_fd_t fd;
+ p_self->b_stream_connected = tsk_false;
+ p_self->b_stream_error = tsk_false;
+ fd = tnet_transport_connectto_3(p_self->p_transport, p_self->p_lcl_sock, p_self->p_srv_host, p_self->u_srv_port, p_self->p_lcl_sock->type);
+ if (fd != p_self->p_lcl_sock->fd) {
+ TSK_DEBUG_ERROR("Failed to connect to TURN server(%s:%d)", p_self->p_srv_host, p_self->u_srv_port);
+ ret = -3;
+ goto bail;
+ }
+ TSK_DEBUG_INFO("TURN server connection fd = %d", p_self->p_lcl_sock->fd);
+ }
+
+ p_self->b_started = tsk_true;
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+int tnet_turn_session_allocate(tnet_turn_session_t* p_self)
+{
+ int ret = 0;
+
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started yet");
+ ret = -3;
+ goto bail;
+ }
+
+ // create Allocate Request
+ p_self->e_alloc_state = tnet_stun_state_none;
+ p_self->timer.rtt.alloc.id = TSK_INVALID_TIMER_ID;
+ TSK_OBJECT_SAFE_FREE(p_self->p_pkt_alloc);
+ if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_allocate_request, &p_self->p_pkt_alloc))) {
+ TSK_DEBUG_ERROR("Failed to create TURN Allocate request");
+ goto bail;
+ }
+ // add attributes
+ p_self->p_pkt_alloc->opt.dontfrag = 0;
+ ret = tnet_stun_pkt_attrs_add(p_self->p_pkt_alloc,
+ TNET_STUN_PKT_ATTR_ADD_LIFETIME(p_self->u_lifetime_alloc_in_sec),
+ TNET_STUN_PKT_ATTR_ADD_REQUESTED_TRANSPORT(p_self->e_req_transport),
+ TNET_STUN_PKT_ATTR_ADD_SOFTWARE_ZT(kStunSoftware), // recommended for Alloc and Refresh
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+
+ if ((ret = _tnet_turn_session_send_pkt(p_self, p_self->p_pkt_alloc))) {
+ goto bail;
+ }
+ if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->p_lcl_sock->type)) {
+ p_self->timer.rtt.alloc.u_timeout = kStunUdpRetransmitTimoutMinInMs;
+ TNET_TURN_SESSION_TIMER_SCHEDULE_MILLIS(p_self, p_self->timer.rtt.alloc.id, p_self->timer.rtt.alloc.u_timeout);
+ }
+ p_self->e_alloc_state = tnet_stun_state_trying;
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+int tnet_turn_session_get_relayed_addr(const struct tnet_turn_session_s* p_self, char** pp_ip, uint16_t *pu_port, tsk_bool_t *pb_ipv6)
+{
+ int ret = 0;
+
+ if (!p_self || !pp_ip || !pu_port || !pb_ipv6) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started yet");
+ ret = -3;
+ goto bail;
+ }
+ if (p_self->e_alloc_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN allocation yet");
+ ret = -4;
+ goto bail;
+ }
+
+ tsk_strupdate(pp_ip, p_self->p_rel_ip);
+ *pu_port = p_self->u_rel_port;
+ *pb_ipv6 = p_self->b_rel_ipv6;
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+int tnet_turn_session_get_srflx_addr(const tnet_turn_session_t* p_self, char** pp_ip, uint16_t *pu_port, tsk_bool_t *pb_ipv6)
+{
+ int ret = 0;
+
+ if (!p_self || !pp_ip || !pu_port || !pb_ipv6) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started yet");
+ ret = -3;
+ goto bail;
+ }
+ if (p_self->e_alloc_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN allocation yet");
+ ret = -4;
+ goto bail;
+ }
+
+ tsk_strupdate(pp_ip, p_self->p_srflx_ip);
+ *pu_port = p_self->u_srflx_port;
+ *pb_ipv6 = p_self->b_srflx_ipv6;
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+int tnet_turn_session_get_state_alloc(const struct tnet_turn_session_s* pc_self, enum tnet_stun_state_e *pe_state)
+{
+ if (!pc_self || !pe_state) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *pe_state = pc_self->e_alloc_state;
+ return 0;
+}
+
+int tnet_turn_session_get_socket_local(struct tnet_turn_session_s* p_self, struct tnet_socket_s** pp_lcl_sock)
+{
+ if (!p_self || !pp_lcl_sock) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(p_self);
+ *pp_lcl_sock = (struct tnet_socket_s*)tsk_object_ref(p_self->p_lcl_sock);
+ tsk_safeobj_unlock(p_self);
+ return 0;
+}
+
+int tnet_turn_session_get_state_createperm(const struct tnet_turn_session_s* pc_self, tnet_turn_peer_id_t u_peer_id, enum tnet_stun_state_e *pe_state)
+{
+ const tnet_turn_peer_t *pc_peer;
+ if (!pc_self || !pe_state) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(pc_self);
+ if ((pc_peer = tsk_list_find_object_by_pred(pc_self->p_list_peers, __pred_find_peer_by_id, &u_peer_id))) {
+ *pe_state = pc_peer->e_createperm_state;
+ }
+ else {
+ *pe_state = tnet_stun_state_none;
+ if (u_peer_id != kTurnPeerIdInvalid) {
+ TSK_DEBUG_WARN("TURN peer with id =%ld doesn't exist", u_peer_id);
+ }
+ }
+ tsk_safeobj_unlock(pc_self);
+ return 0;
+}
+
+int tnet_turn_session_get_state_connbind(const struct tnet_turn_session_s* pc_self, tnet_turn_peer_id_t u_peer_id, enum tnet_stun_state_e *pe_state)
+{
+ const tnet_turn_peer_t *pc_peer;
+ if (!pc_self || !pe_state) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(pc_self);
+ if ((pc_peer = tsk_list_find_object_by_pred(pc_self->p_list_peers, __pred_find_peer_by_id, &u_peer_id))) {
+ *pe_state = pc_peer->e_connbind_state;
+ }
+ else {
+ *pe_state = tnet_stun_state_none;
+ if (u_peer_id != kTurnPeerIdInvalid) {
+ TSK_DEBUG_WARN("TURN peer with id =%ld doesn't exist", u_peer_id);
+ }
+ }
+ tsk_safeobj_unlock(pc_self);
+ return 0;
+}
+
+int tnet_turn_session_get_req_transport(const struct tnet_turn_session_s* pc_self, enum tnet_turn_transport_e *pe_transport)
+{
+ if (!pc_self || !pe_transport) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(pc_self);
+ *pe_transport = pc_self->e_req_transport;
+ tsk_safeobj_unlock(pc_self);
+ return 0;
+}
+
+int tnet_turn_session_get_bytes_count(const struct tnet_turn_session_s* pc_self, uint64_t* bytes_in, uint64_t* bytes_out)
+{
+ if (!pc_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return tnet_transport_get_bytes_count(pc_self->p_transport, bytes_in, bytes_out);
+}
+
+int tnet_turn_session_createpermission(struct tnet_turn_session_s* p_self, const char* pc_peer_addr, uint16_t u_peer_port, tnet_turn_peer_id_t* pu_id)
+{
+ int ret = 0;
+ tnet_turn_peer_t *p_peer = tsk_null;
+
+ if (!p_self || !pc_peer_addr || !u_peer_port || !pu_id) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started yet");
+ ret = -3;
+ goto bail;
+ }
+ if (p_self->e_alloc_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN allocation yet");
+ ret = -4;
+ goto bail;
+ }
+ if ((ret = _tnet_turn_peer_create(pc_peer_addr, u_peer_port, TNET_SOCKET_TYPE_IS_IPV6(p_self->p_lcl_sock->type), &p_peer))) {
+ goto bail;
+ }
+ if (TNET_SOCKET_TYPE_IS_STREAM(p_self->p_lcl_sock->type)) {
+ if (!p_peer->p_stream_buff_in && !(p_peer->p_stream_buff_in = tsk_buffer_create_null())) {
+ TSK_DEBUG_ERROR("Failed to create stream buffer for peer with id=%ld", p_peer->id);
+ ret = -5;
+ goto bail;
+ }
+ }
+ if ((ret = _tnet_turn_session_send_permission(p_self, p_peer))) {
+ goto bail;
+ }
+ *pu_id = p_peer->id;
+ tsk_list_push_back_data(p_self->p_list_peers, (void**)&p_peer);
+
+bail:
+ TSK_OBJECT_SAFE_FREE(p_peer);
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+int tnet_turn_session_deletepermission(struct tnet_turn_session_s* p_self, tnet_turn_peer_id_t u_id)
+{
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(p_self);
+ tsk_list_remove_item_by_pred(p_self->p_list_peers, __pred_find_peer_by_id, &u_id);
+ tsk_safeobj_unlock(p_self);
+ return 0;
+}
+
+int tnet_turn_session_chanbind(tnet_turn_session_t* p_self, tnet_turn_peer_id_t u_peer_id)
+{
+ int ret = 0;
+ tnet_turn_peer_t *pc_peer;
+
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started yet");
+ ret = -3;
+ goto bail;
+ }
+ if (p_self->e_alloc_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN allocation yet");
+ ret = -4;
+ goto bail;
+ }
+ if (!(pc_peer = (tnet_turn_peer_t *)tsk_list_find_object_by_pred(p_self->p_list_peers, __pred_find_peer_by_id, &u_peer_id))) {
+ TSK_DEBUG_ERROR("Cannot find TURN peer with id = %ld", u_peer_id);
+ ret = -5;
+ goto bail;
+ }
+
+ // ChannelBind must not be used for streams (e.g. TCP, TLS....)
+ if (p_self->e_req_transport != tnet_turn_transport_udp) {
+ TSK_DEBUG_ERROR("TURN ChannelBind not supported for stream");
+ ret = -6;
+ goto bail;
+ }
+
+ // create ChannelBind Request if doesn't exist (ChannelBind refresh *must* have same id)
+ pc_peer->e_chanbind_state = tnet_stun_state_none;
+ pc_peer->timer.rtt.chanbind.id = TSK_INVALID_TIMER_ID;
+ if (!pc_peer->p_pkt_chanbind) {
+ pc_peer->u_chan_num = _tnet_turn_session_get_unique_chan_num();
+ if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_channelbind_request, &pc_peer->p_pkt_chanbind))) {
+ TSK_DEBUG_ERROR("Failed to create TURN ChannelBind request");
+ goto bail;
+ }
+ // add authentication info
+ tnet_stun_pkt_auth_copy(pc_peer->p_pkt_chanbind, p_self->cred.p_usr_name, p_self->cred.p_pwd, p_self->p_pkt_alloc);
+ // add attributes
+ pc_peer->p_pkt_chanbind->opt.dontfrag = 0;
+ ret = tnet_stun_pkt_attrs_add(pc_peer->p_pkt_chanbind,
+ /* Must not add LIFETIME and there is no way to delete permission */
+ TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(pc_peer->b_ipv6 ? tnet_stun_address_family_ipv6 : tnet_stun_address_family_ipv4, pc_peer->u_addr_port, &pc_peer->addr_ip),
+ TNET_STUN_PKT_ATTR_ADD_CHANNEL_NUMBER(pc_peer->u_chan_num),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+
+ }
+ else {
+ if ((ret = tnet_stun_utils_transac_id_rand(&pc_peer->p_pkt_chanbind->transac_id))) {
+ goto bail;
+ }
+ }
+
+ if ((ret = _tnet_turn_session_send_pkt(p_self, pc_peer->p_pkt_chanbind))) {
+ goto bail;
+ }
+ if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->p_lcl_sock->type)) {
+ pc_peer->timer.rtt.chanbind.u_timeout = kStunUdpRetransmitTimoutMinInMs;
+ TNET_TURN_SESSION_TIMER_SCHEDULE_MILLIS(p_self, pc_peer->timer.rtt.chanbind.id, pc_peer->timer.rtt.chanbind.u_timeout);
+ }
+ pc_peer->e_chanbind_state = tnet_stun_state_trying;
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+// TCP-Connect rfc6062 - 4.3. Initiating a Connection
+int tnet_turn_session_connect(struct tnet_turn_session_s* p_self, tnet_turn_peer_id_t u_peer_id)
+{
+ int ret = 0;
+ tnet_turn_peer_t *pc_peer;
+
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started yet");
+ ret = -3;
+ goto bail;
+ }
+ if (p_self->e_alloc_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN allocation yet");
+ ret = -4;
+ goto bail;
+ }
+ if (!(pc_peer = (tnet_turn_peer_t *)tsk_list_find_object_by_pred(p_self->p_list_peers, __pred_find_peer_by_id, &u_peer_id))) {
+ TSK_DEBUG_ERROR("Cannot find TURN peer with id = %ld", u_peer_id);
+ ret = -5;
+ goto bail;
+ }
+
+ // Connect must be used for streams (e.g. TCP, TLS....) only
+ if (p_self->e_req_transport != tnet_turn_transport_tcp) {
+ TSK_DEBUG_ERROR("TURN Connect not supported for UDP relay");
+ ret = -6;
+ goto bail;
+ }
+
+ // create Connect Request if doesn't exist (Connect refresh *must* have same id)
+ pc_peer->e_connect_state = tnet_stun_state_none;
+ pc_peer->e_connbind_state = tnet_stun_state_none;
+ if (!pc_peer->p_pkt_connect) {
+ if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_connect_request, &pc_peer->p_pkt_connect))) {
+ TSK_DEBUG_ERROR("Failed to create TURN Connect request");
+ goto bail;
+ }
+ // add authentication info
+ tnet_stun_pkt_auth_copy(pc_peer->p_pkt_connect, p_self->cred.p_usr_name, p_self->cred.p_pwd, p_self->p_pkt_alloc);
+ // add attributes
+ pc_peer->p_pkt_connect->opt.dontfrag = 0;
+ ret = tnet_stun_pkt_attrs_add(pc_peer->p_pkt_connect,
+ /* Must not add LIFETIME and there is no way to delete permission */
+ TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(pc_peer->b_ipv6 ? tnet_stun_address_family_ipv6 : tnet_stun_address_family_ipv4, pc_peer->u_addr_port, &pc_peer->addr_ip),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+
+ }
+ else {
+ if ((ret = tnet_stun_utils_transac_id_rand(&pc_peer->p_pkt_connect->transac_id))) {
+ goto bail;
+ }
+ }
+
+ if ((ret = _tnet_turn_session_send_pkt(p_self, pc_peer->p_pkt_connect))) {
+ goto bail;
+ }
+ pc_peer->e_connect_state = tnet_stun_state_trying;
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+int tnet_turn_session_send_data(tnet_turn_session_t* p_self, tnet_turn_peer_id_t u_peer_id, const void* pc_data_ptr, uint16_t u_data_size)
+{
+ int ret = 0;
+ tnet_turn_peer_t* pc_peer;
+
+ if (!p_self || !pc_data_ptr || !u_data_size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started yet");
+ ret = -3;
+ goto bail;
+ }
+ if (p_self->e_alloc_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN allocation yet");
+ ret = -3;
+ goto bail;
+ }
+ if (!(pc_peer = (tnet_turn_peer_t *)tsk_list_find_object_by_pred(p_self->p_list_peers, __pred_find_peer_by_id, &u_peer_id))) {
+ TSK_DEBUG_ERROR("Cannot find TURN peer with id = %ld", u_peer_id);
+ ret = -4;
+ goto bail;
+ }
+ if (pc_peer->e_createperm_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN permission for the remote peer");
+ ret = -5;
+ goto bail;
+ }
+
+ /** Send Stream **/
+ if (TNET_SOCKET_TYPE_IS_STREAM(p_self->p_lcl_sock->type) && p_self->e_req_transport == tnet_turn_transport_tcp) {
+ ret = _tnet_turn_session_send_stream_raw(p_self, pc_peer, pc_data_ptr, u_data_size);
+ goto bail;
+ }
+
+ /*** ChannelData ***/
+ if (pc_peer->e_chanbind_state == tnet_stun_state_ok) {
+ ret = _tnet_turn_session_send_chandata(p_self, pc_peer, pc_data_ptr, u_data_size);
+ goto bail;
+ }
+
+ /*** Send indication ***/
+ if (!pc_peer->p_pkt_sendind) {
+ if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_send_indication, &pc_peer->p_pkt_sendind))) {
+ TSK_DEBUG_ERROR("Failed to create TURN SendIndication request");
+ goto bail;
+ }
+ pc_peer->p_pkt_sendind->opt.dontfrag = 0;
+ // add authinfo
+ tnet_stun_pkt_auth_copy(pc_peer->p_pkt_sendind, p_self->cred.p_usr_name, p_self->cred.p_pwd, p_self->p_pkt_alloc);
+ // add attributes
+ ret = tnet_stun_pkt_attrs_add(pc_peer->p_pkt_sendind,
+ TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(pc_peer->b_ipv6 ? tnet_stun_address_family_ipv6 : tnet_stun_address_family_ipv4, pc_peer->u_addr_port, &pc_peer->addr_ip),
+ TNET_STUN_PKT_ATTR_ADD_DATA(pc_data_ptr, u_data_size),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ }
+ else {
+ const tnet_stun_attr_vdata_t *pc_attr_data;
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_peer->p_pkt_sendind, tnet_stun_attr_type_data, (const tnet_stun_attr_t**)&pc_attr_data))) {
+ goto bail;
+ }
+ if (!pc_attr_data) {
+ ret = tnet_stun_pkt_attrs_add(pc_peer->p_pkt_sendind,
+ TNET_STUN_PKT_ATTR_ADD_DATA(pc_data_ptr, u_data_size),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ }
+ else {
+ if ((ret = tnet_stun_attr_vdata_update((tnet_stun_attr_vdata_t*)pc_attr_data, pc_data_ptr, u_data_size))) {
+ goto bail;
+ }
+ }
+ if ((ret = tnet_stun_utils_transac_id_rand(&pc_peer->p_pkt_sendind->transac_id))) {
+ goto bail;
+ }
+ }
+ if ((ret = _tnet_turn_session_send_pkt_0(p_self, pc_peer, pc_peer->p_pkt_sendind))) {
+ goto bail;
+ }
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+int tnet_turn_session_is_active(const struct tnet_turn_session_s* pc_self, tnet_turn_peer_id_t u_peer_id, tsk_bool_t *pb_active)
+{
+ if (!pc_self || !pb_active) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(pc_self);
+ *pb_active = pc_self->b_started
+ && (pc_self->e_alloc_state == tnet_stun_state_ok);
+ if (*pb_active) {
+ const tnet_turn_peer_t* pc_peer;
+ if ((pc_peer = (const tnet_turn_peer_t *)tsk_list_find_object_by_pred(pc_self->p_list_peers, __pred_find_peer_by_id, &u_peer_id))) {
+ *pb_active = (pc_peer->e_createperm_state == tnet_stun_state_ok);
+ }
+ else {
+ *pb_active = tsk_false;
+ }
+ }
+ tsk_safeobj_unlock(pc_self);
+ return 0;
+}
+
+int tnet_turn_session_is_stream(const struct tnet_turn_session_s* pc_self, tsk_bool_t *pb_stream)
+{
+ if (!pc_self || !pb_stream) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(pc_self);
+ *pb_stream = TNET_SOCKET_TYPE_IS_STREAM(pc_self->p_lcl_sock->type) ? tsk_true : tsk_false;
+ tsk_safeobj_unlock(pc_self);
+ return 0;
+}
+
+// Check "ConnectionBind" sent and underlaying socket is connected
+int tnet_turn_session_is_stream_connected(const struct tnet_turn_session_s* pc_self, tnet_turn_peer_id_t u_peer_id, tsk_bool_t *pb_connected)
+{
+ if (!pc_self || !pb_connected) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(pc_self);
+ *pb_connected = pc_self->b_started
+ && (pc_self->e_alloc_state == tnet_stun_state_ok);
+ if (*pb_connected) {
+ const tnet_turn_peer_t* pc_peer;
+ if ((pc_peer = (const tnet_turn_peer_t *)tsk_list_find_object_by_pred(pc_self->p_list_peers, __pred_find_peer_by_id, &u_peer_id))) {
+ *pb_connected = (pc_peer->conn_fd != TNET_INVALID_FD && pc_peer->b_stream_connected && pc_peer->e_connbind_state == tnet_stun_state_ok);
+ }
+ else {
+ *pb_connected = tsk_false;
+ }
+ }
+ tsk_safeobj_unlock(pc_self);
+ return 0;
+}
+
+int tnet_turn_session_stop(tnet_turn_session_t* p_self)
+{
+ int ret = 0;
+
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // FIXME
+ // tsk_safeobj_lock(p_self);
+
+ p_self->b_stopping = tsk_true;
+
+ if (p_self->e_alloc_state == tnet_stun_state_ok) {
+ // UnAlloc
+ p_self->u_lifetime_alloc_in_sec = 0;
+ _tnet_turn_session_send_refresh(p_self);
+ }
+
+ if (p_self->timer.p_mgr) {
+ ret = tsk_timer_manager_stop(p_self->timer.p_mgr);
+ }
+
+ // free transport to force next call to prepare() to create new one with new sockets
+ if (p_self->p_transport) {
+ tnet_transport_shutdown(p_self->p_transport);
+ TSK_OBJECT_SAFE_FREE(p_self->p_transport);
+ }
+
+ // clear peers
+ tsk_list_clear_items(p_self->p_list_peers);
+
+ p_self->b_prepared = tsk_false;
+ p_self->b_started = tsk_false;
+ p_self->b_stopping = tsk_false;
+
+ // tsk_safeobj_unlock(p_self);
+
+ return ret;
+}
+
+static int _tnet_turn_session_peer_find_by_id(const tnet_turn_session_t* pc_self, tnet_turn_peer_id_t id, const struct tnet_turn_peer_s **ppc_peer)
+{
+ const tsk_list_item_t *pc_item;
+ const struct tnet_turn_peer_s *pc_peer;
+ if (!pc_self || !ppc_peer) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *ppc_peer = tsk_null;
+ tsk_list_foreach(pc_item, pc_self->p_list_peers) {
+ if (!(pc_peer = pc_item->data)) {
+ continue;
+ }
+ if (pc_peer->id == id) {
+ *ppc_peer = pc_peer;
+ break;
+ }
+ }
+ return 0;
+}
+
+static int _tnet_turn_session_peer_find_by_timer(const tnet_turn_session_t* pc_self, tsk_timer_id_t id, const struct tnet_turn_peer_s **ppc_peer)
+{
+ const tsk_list_item_t *pc_item;
+ const struct tnet_turn_peer_s *pc_peer;
+ if (!pc_self || !ppc_peer) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *ppc_peer = tsk_null;
+ tsk_list_foreach(pc_item, pc_self->p_list_peers) {
+ if (!(pc_peer = pc_item->data)) {
+ continue;
+ }
+ if (pc_peer->timer.rtt.chanbind.id == id || pc_peer->timer.rtt.createperm.id == id) {
+ *ppc_peer = pc_peer;
+ break;
+ }
+ }
+ return 0;
+}
+
+static uint16_t _tnet_turn_session_get_unique_chan_num()
+{
+ // rfc5766 - The channel number is in the range 0x4000 through 0x7FFE (inclusive)
+ static long __l_chan_num = 0;
+ tsk_atomic_inc(&__l_chan_num);
+ return (__l_chan_num % (0x7FFE - 0x4000)) + 0x4000;
+}
+
+static int _tnet_turn_session_send_chandata(tnet_turn_session_t* p_self, const tnet_turn_peer_t* pc_peer, const void* pc_buff_ptr, tsk_size_t u_buff_size)
+{
+ int ret = 0;
+ tsk_size_t PadSize, NeededSize;
+ uint8_t* _p_buff_chandata_ptr;
+ if (!p_self || !pc_peer || !pc_buff_ptr || !u_buff_size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // lock()
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started");
+ ret = -2;
+ goto bail;
+ }
+ if (pc_peer->e_chanbind_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN data channel for peer id = %ld", pc_peer->id);
+ ret = -3;
+ goto bail;
+ }
+
+ // rfc5766 - 11.5. Sending a ChannelData Message
+ if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->p_lcl_sock->type)) {
+ // Over UDP, the padding is not required but MAY be included.
+ PadSize = 0;
+ }
+ else {
+ // Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to
+ // a multiple of four bytes in order to ensure the alignment of subsequent messages.
+ PadSize = (u_buff_size & 0x03) ? (4 - (u_buff_size & 0x03)) : 0;
+ }
+ NeededSize = kStunChannelDataHdrSizeInOctets + u_buff_size + PadSize;
+
+ if (p_self->u_buff_chandata_size < NeededSize) {
+ if (!(p_self->p_buff_chandata_ptr = tsk_realloc(p_self->p_buff_chandata_ptr, NeededSize))) {
+ p_self->u_buff_chandata_size = 0;
+ ret = -4;
+ goto bail;
+ }
+ p_self->u_buff_chandata_size = NeededSize;
+ }
+ _p_buff_chandata_ptr = (uint8_t*)p_self->p_buff_chandata_ptr;
+
+ *((uint16_t*)&_p_buff_chandata_ptr[0]) = tnet_htons(pc_peer->u_chan_num); // Channel Number
+ *((uint16_t*)&_p_buff_chandata_ptr[2]) = tnet_htons((uint16_t)u_buff_size); // Length
+ memcpy(&_p_buff_chandata_ptr[kStunChannelDataHdrSizeInOctets], pc_buff_ptr, u_buff_size); // Application Data
+ if (PadSize) {
+ memset(&_p_buff_chandata_ptr[kStunChannelDataHdrSizeInOctets + u_buff_size], 0, PadSize); // Set padding bytes to zero (not required but ease debugging)
+ }
+
+ if ((ret = _tnet_turn_session_send_buff_0(p_self, pc_peer, p_self->p_buff_chandata_ptr, NeededSize))) {
+ goto bail;
+ }
+
+bail:
+ // unlock()
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+static int _tnet_turn_session_send_stream_raw(tnet_turn_session_t* p_self, tnet_turn_peer_t* pc_peer, const void* pc_buff_ptr, tsk_size_t u_buff_size)
+{
+ int ret = 0;
+ if (!p_self || !pc_peer || !pc_buff_ptr || !u_buff_size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // lock()
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started");
+ ret = -2;
+ goto bail;
+ }
+ if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->p_lcl_sock->type)) {
+ TSK_DEBUG_ERROR("Must not call this function for non-stream transports");
+ ret = -3;
+ goto bail;
+ }
+ if (pc_peer->e_connbind_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN TCP connection for peer id = %ld", pc_peer->id);
+ ret = -4;
+ goto bail;
+ }
+
+ if ((ret = _tnet_turn_session_send_buff_0(p_self, pc_peer, pc_buff_ptr, u_buff_size))) {
+ goto bail;
+ }
+
+bail:
+ // unlock()
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+static int _tnet_turn_session_send_refresh(tnet_turn_session_t* p_self)
+{
+ int ret = 0;
+
+ if (!p_self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started yet");
+ ret = -3;
+ goto bail;
+ }
+ if (p_self->e_alloc_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN allocation yet");
+ ret = -4;
+ goto bail;
+ }
+
+ p_self->e_refresh_state = tnet_stun_state_none;
+ // create RefreshIndication Request
+ p_self->timer.rtt.refresh.id = TSK_INVALID_TIMER_ID;
+ TSK_OBJECT_SAFE_FREE(p_self->p_pkt_refresh);
+ if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_refresh_request, &p_self->p_pkt_refresh))) {
+ TSK_DEBUG_ERROR("Failed to create TURN RefreshIndication request");
+ goto bail;
+ }
+ // add authentication info
+ tnet_stun_pkt_auth_copy(p_self->p_pkt_refresh, p_self->cred.p_usr_name, p_self->cred.p_pwd, p_self->p_pkt_alloc);
+#if 0
+ if (p_self->u_lifetime_alloc_in_sec == 0) {
+ const tnet_stun_attr_vdata_t *pc_attr_nonce = tsk_null;
+ tnet_stun_pkt_attr_find_first(p_self->p_pkt_refresh, tnet_stun_attr_type_nonce, (const tnet_stun_attr_t**)&pc_attr_nonce);
+ if (pc_attr_nonce) {
+ pc_attr_nonce->p_data_ptr[0] = 'a';
+ }
+ }
+#endif
+ // add attributes
+ ret = tnet_stun_pkt_attrs_add(p_self->p_pkt_refresh,
+ TNET_STUN_PKT_ATTR_ADD_LIFETIME(p_self->u_lifetime_alloc_in_sec),
+ TNET_STUN_PKT_ATTR_ADD_SOFTWARE_ZT(kStunSoftware), // recommended for Alloc and Refresh
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+ p_self->p_pkt_refresh->opt.dontfrag = 0;
+ p_self->p_pkt_refresh->opt.fingerprint = 0;
+ if ((ret = _tnet_turn_session_send_pkt(p_self, p_self->p_pkt_refresh))) {
+ goto bail;
+ }
+ if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->p_lcl_sock->type)) {
+ p_self->timer.rtt.refresh.u_timeout = kStunUdpRetransmitTimoutMinInMs;
+ TNET_TURN_SESSION_TIMER_SCHEDULE_MILLIS(p_self, p_self->timer.rtt.refresh.id, p_self->timer.rtt.refresh.u_timeout);
+ }
+ p_self->e_refresh_state = tnet_stun_state_trying;
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+static int _tnet_turn_session_send_permission(struct tnet_turn_session_s* p_self, tnet_turn_peer_t *p_peer)
+{
+ int ret = 0;
+ if (!p_self || !p_peer) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started yet");
+ ret = -3;
+ goto bail;
+ }
+ if (p_self->e_alloc_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN allocation yet");
+ ret = -4;
+ goto bail;
+ }
+
+ // create CreatePermission Request
+ p_peer->e_createperm_state = tnet_stun_state_none;
+ p_peer->timer.rtt.createperm.id = TSK_INVALID_TIMER_ID;
+ TSK_OBJECT_SAFE_FREE(p_peer->p_pkt_createperm);
+ if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_createpermission_request, &p_peer->p_pkt_createperm))) {
+ TSK_DEBUG_ERROR("Failed to create TURN CreatePermission request");
+ goto bail;
+ }
+ // add authinfo
+ tnet_stun_pkt_auth_copy(p_peer->p_pkt_createperm, p_self->cred.p_usr_name, p_self->cred.p_pwd, p_self->p_pkt_alloc);
+ // add attributes
+ p_peer->p_pkt_createperm->opt.dontfrag = 0;
+ ret = tnet_stun_pkt_attrs_add(p_peer->p_pkt_createperm,
+ /* Must not add LIFETIME and there is no way to delete permission */
+ TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(p_peer->b_ipv6 ? tnet_stun_address_family_ipv6 : tnet_stun_address_family_ipv4, p_peer->u_addr_port, &p_peer->addr_ip),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+
+ if ((ret = _tnet_turn_session_send_pkt(p_self, p_peer->p_pkt_createperm))) {
+ goto bail;
+ }
+ if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->p_lcl_sock->type)) {
+ p_peer->timer.rtt.createperm.u_timeout = kStunUdpRetransmitTimoutMinInMs;
+ TNET_TURN_SESSION_TIMER_SCHEDULE_MILLIS(p_self, p_peer->timer.rtt.createperm.id, p_peer->timer.rtt.createperm.u_timeout);
+ }
+ p_peer->e_createperm_state = tnet_stun_state_trying;
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+// TCP-Connect rfc6062 - 4.3. Initiating a Connection
+static int _tnet_turn_session_send_connbind(struct tnet_turn_session_s* p_self, tnet_turn_peer_t *p_peer)
+{
+ int ret = 0;
+
+ if (!p_self || !p_peer) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started yet");
+ ret = -3;
+ goto bail;
+ }
+ if (p_self->e_alloc_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN allocation yet");
+ ret = -4;
+ goto bail;
+ }
+
+ // ConnectionBind must be sent after Connect
+ if (p_peer->e_connect_state != tnet_stun_state_ok) {
+ TSK_DEBUG_ERROR("No active TURN connection yet");
+ ret = -6;
+ goto bail;
+ }
+
+ // Connect must be used for streams (e.g. TCP, TLS....) only
+ if (p_self->e_req_transport != tnet_turn_transport_tcp) {
+ TSK_DEBUG_ERROR("TURN ConnectionBind not supported for UDP transport");
+ ret = -7;
+ goto bail;
+ }
+
+ // create Connect Request if doesn't exist (Connect refresh *must* have same id)
+ p_peer->e_connbind_state = tnet_stun_state_none;
+ if (!p_peer->p_pkt_connbind) {
+ if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_connectionbind_request, &p_peer->p_pkt_connbind))) {
+ TSK_DEBUG_ERROR("Failed to create TURN ConnectionBind request");
+ goto bail;
+ }
+ // add authentication info
+ tnet_stun_pkt_auth_copy(p_peer->p_pkt_connbind, p_self->cred.p_usr_name, p_self->cred.p_pwd, p_self->p_pkt_alloc);
+ // add attributes
+ p_peer->p_pkt_connbind->opt.dontfrag = 0;
+ ret = tnet_stun_pkt_attrs_add(p_peer->p_pkt_connbind,
+ // Error "420" when XOR-PEER-ADDRESS attribute is added to ConnectionBind request
+ /* TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(p_peer->b_ipv6 ? tnet_stun_address_family_ipv6 : tnet_stun_address_family_ipv4, p_peer->u_addr_port, &p_peer->addr_ip), */
+ TNET_STUN_PKT_ATTR_ADD_CONNECTION_ID(p_peer->u_conn_id),
+ TNET_STUN_PKT_ATTR_ADD_NULL());
+ if (ret) {
+ goto bail;
+ }
+
+ }
+ else {
+ if ((ret = tnet_stun_utils_transac_id_rand(&p_peer->p_pkt_connbind->transac_id))) {
+ goto bail;
+ }
+ }
+
+ if ((ret = _tnet_turn_session_send_pkt_0(p_self, p_peer, p_peer->p_pkt_connbind))) {
+ goto bail;
+ }
+ p_peer->e_connbind_state = tnet_stun_state_trying;
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+static int _tnet_turn_session_send_buff_0(tnet_turn_session_t* p_self, const tnet_turn_peer_t* pc_peer, const void* pc_buff_ptr, tsk_size_t u_buff_size)
+{
+ int ret = 0;
+ tsk_size_t u_sent_bytes = 0;
+ if (!p_self || !pc_buff_ptr || !u_buff_size) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // lock()
+ tsk_safeobj_lock(p_self);
+
+ if (!p_self->b_started) {
+ TSK_DEBUG_ERROR("TURN session not started");
+ ret = -2;
+ goto bail;
+ }
+
+ if (TNET_SOCKET_TYPE_IS_DGRAM(p_self->p_lcl_sock->type)) {
+#if 1
+ u_sent_bytes = tnet_transport_sendto(p_self->p_transport, p_self->p_lcl_sock->fd, (const struct sockaddr *)&p_self->srv_addr, pc_buff_ptr, u_buff_size);
+#else
+ u_sent_bytes = tnet_sockfd_sendto(p_self->p_lcl_sock->fd, (const struct sockaddr *)&p_self->srv_addr, pc_buff_ptr, u_buff_size);
+#endif
+ }
+ else {
+ if (pc_peer && pc_peer->b_stream_connected && pc_peer->conn_fd != TNET_INVALID_FD) {
+ // Send using Peer connection if connected
+ // Should never be called because for now requested transport is always equal to UDP
+#if 1
+ u_sent_bytes = tnet_transport_send(p_self->p_transport, pc_peer->conn_fd, pc_buff_ptr, u_buff_size);
+#else
+ u_sent_bytes = tnet_sockfd_send(pc_peer->conn_fd, pc_buff_ptr, u_buff_size, 0);
+#endif
+ }
+ else {
+ tsk_bool_t b_delay_send = tsk_false;
+ // Connect if not already done
+ if (!p_self->b_stream_connected) {
+ ret = tnet_sockfd_waitUntilWritable(p_self->p_lcl_sock->fd, kTurnTransportConnectTimeout);
+ if (ret == 0) { // socket is valid but not connected (e.g. Proxy handshaking not completed yet)
+ TSK_DEBUG_INFO("Saving %u TURN bytes and waiting for 'connected' event before sending", (unsigned)u_buff_size);
+ if (!p_self->p_stream_buff_out && !(p_self->p_stream_buff_out = tsk_buffer_create_null())) {
+ TSK_DEBUG_ERROR("Failed to create buffer");
+ ret = -3;
+ goto bail;
+ }
+ if ((p_self->p_stream_buff_out->size + u_buff_size) > kTurnStreamOutMaxSize) {
+ TSK_DEBUG_ERROR("To much pending data");
+ ret = -5;
+ goto bail;
+ }
+ tsk_buffer_append(p_self->p_stream_buff_out, pc_buff_ptr, u_buff_size);
+ b_delay_send = tsk_true;
+ u_sent_bytes = u_buff_size;
+ }
+ else {
+ TSK_DEBUG_ERROR("Socket in invalid state");
+ ret = -6;
+ goto bail;
+ }
+ }
+ if (!b_delay_send && p_self->b_stream_connected) {
+#if 1
+ u_sent_bytes = tnet_transport_send(p_self->p_transport, p_self->p_lcl_sock->fd, pc_buff_ptr, u_buff_size);
+#else
+ u_sent_bytes = tnet_socket_send_stream(p_self->p_lcl_sock, pc_buff_ptr, u_buff_size);
+#endif
+ }
+ }
+ }
+ if (u_sent_bytes != u_buff_size) {
+ TSK_DEBUG_ERROR("Failed to send %u bytes. Only %u sent", (unsigned)u_buff_size, (unsigned)u_sent_bytes);
+ ret = -2;
+ goto bail;
+ }
+
+bail:
+ // unlock()
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+static int _tnet_turn_session_send_buff(tnet_turn_session_t* p_self, const void* pc_buff_ptr, tsk_size_t u_buff_size)
+{
+ return _tnet_turn_session_send_buff_0(p_self, tsk_null/*peer*/, pc_buff_ptr, u_buff_size);
+}
+
+static int _tnet_turn_session_send_pkt_0(tnet_turn_session_t* p_self, const tnet_turn_peer_t* pc_peer, const tnet_turn_pkt_t *pc_pkt)
+{
+ int ret;
+ tsk_size_t u_min_size;
+ if (!p_self || !pc_pkt) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(p_self);
+
+ if ((ret = tnet_stun_pkt_get_size_in_octetunits_with_padding(pc_pkt, &u_min_size))) {
+ goto bail;
+ }
+ u_min_size += kStunBuffMinPad;
+ if (p_self->u_buff_send_size < u_min_size) {
+ if (!(p_self->p_buff_send_ptr = tsk_realloc(p_self->p_buff_send_ptr, u_min_size))) {
+ TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", (unsigned)u_min_size);
+ ret = -3;
+ p_self->u_buff_send_size = 0;
+ goto bail;
+ }
+ p_self->u_buff_send_size = u_min_size;
+ }
+
+ if ((ret = tnet_stun_pkt_write_with_padding(pc_pkt, p_self->p_buff_send_ptr, p_self->u_buff_send_size, &u_min_size))) {
+ goto bail;
+ }
+ if ((ret = _tnet_turn_session_send_buff_0(p_self, pc_peer, p_self->p_buff_send_ptr, u_min_size))) {
+ goto bail;
+ }
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+static int _tnet_turn_session_send_pkt(tnet_turn_session_t* p_self, const tnet_turn_pkt_t *pc_pkt)
+{
+ return _tnet_turn_session_send_pkt_0(p_self, tsk_null/*peer*/, pc_pkt);
+}
+
+// 420 = Unknown Attribute
+int _tnet_turn_session_process_err420_pkt(tnet_turn_pkt_t *p_pkt_req, const tnet_turn_pkt_t *pc_pkt_resp420)
+{
+ const tnet_stun_attr_vdata_t* pc_attr;
+ uint16_t u16;
+ int ret;
+ tsk_bool_t b_done = tsk_false;
+ if (!p_pkt_req || !pc_pkt_resp420) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_pkt_resp420, tnet_stun_attr_type_unknown_attrs, (const tnet_stun_attr_t**)&pc_attr))) {
+ goto bail;
+ }
+ if (!pc_attr || !pc_attr->p_data_ptr || (pc_attr->u_data_size & 1)) {
+ TSK_DEBUG_ERROR("UNKNOWN-ATTRIBUTES missing in 420");
+ ret = -3;
+ goto bail;
+ }
+ for (u16 = 0; u16 < pc_attr->u_data_size; u16+=2) {
+ switch (*((uint16_t*)&pc_attr->p_data_ptr[u16])) {
+ case tnet_stun_attr_type_dont_fragment:
+ {
+ p_pkt_req->opt.dontfrag = 0;
+ b_done = tsk_true;
+ break;
+ }
+ case tnet_stun_attr_type_fingerprint:
+ {
+ p_pkt_req->opt.fingerprint = 0;
+ b_done = tsk_true;
+ break;
+ }
+ }
+ }
+
+ if (b_done) {
+ // TRANSACTION-ID
+ if ((ret = tnet_stun_utils_transac_id_rand(&p_pkt_req->transac_id))) {
+ goto bail;
+ }
+ }
+
+bail:
+ return ret;
+}
+
+static int _tnet_turn_session_process_incoming_pkt(struct tnet_turn_session_s* p_self, const tnet_turn_pkt_t *pc_pkt, tsk_bool_t *pb_processed)
+{
+ int ret = 0;
+ if (!p_self || !pc_pkt || !pb_processed) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ *pb_processed = tsk_false;
+
+ // lock()
+ tsk_safeobj_lock(p_self);
+
+ switch (pc_pkt->e_type) {
+ case tnet_stun_pkt_type_allocate_success_response:
+ case tnet_stun_pkt_type_allocate_error_response:
+ case tnet_stun_pkt_type_createpermission_success_response:
+ case tnet_stun_pkt_type_createpermission_error_response:
+ case tnet_stun_pkt_type_channelbind_success_response:
+ case tnet_stun_pkt_type_channelbind_error_response:
+ case tnet_stun_pkt_type_refresh_success_response:
+ case tnet_stun_pkt_type_refresh_error_response:
+ case tnet_stun_pkt_type_connect_success_response:
+ case tnet_stun_pkt_type_connect_error_response:
+ case tnet_stun_pkt_type_connectionbind_success_response:
+ case tnet_stun_pkt_type_connectionbind_error_response:
+ {
+ const tnet_stun_attr_error_code_t* pc_attr_err = tsk_null;
+ uint16_t u_code = 0;
+ tnet_turn_pkt_t *pc_pkt_req = tsk_null;
+ tnet_turn_peer_t* pc_peer = tsk_null;
+
+#define CANCEL_TIMER(parent, which) \
+ if (TSK_TIMER_ID_IS_VALID(parent->timer.rtt.which.id)) { \
+ tsk_timer_manager_cancel(p_self->timer.p_mgr, parent->timer.rtt.which.id); \
+ parent->timer.rtt.which.id = TSK_INVALID_TIMER_ID; \
+ }
+
+ // Find request
+ if (p_self->p_pkt_alloc && tnet_stun_utils_transac_id_cmp(p_self->p_pkt_alloc->transac_id, pc_pkt->transac_id) == 0) {
+ pc_pkt_req = p_self->p_pkt_alloc;
+ CANCEL_TIMER(p_self, alloc);
+ CANCEL_TIMER(p_self, refresh);
+ }
+ else if ((pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_self->p_list_peers, __pred_find_peer_by_transacid_createperm, &pc_pkt->transac_id))) {
+ pc_pkt_req = pc_peer->p_pkt_createperm;
+ CANCEL_TIMER(pc_peer, createperm);
+ }
+ else if ((pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_self->p_list_peers, __pred_find_peer_by_transacid_sendind, &pc_pkt->transac_id))) {
+ pc_pkt_req = pc_peer->p_pkt_sendind;
+ }
+ else if ((pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_self->p_list_peers, __pred_find_peer_by_transacid_chanbind, &pc_pkt->transac_id))) {
+ pc_pkt_req = pc_peer->p_pkt_chanbind;
+ CANCEL_TIMER(pc_peer, chanbind);
+ }
+ else if ((pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_self->p_list_peers, __pred_find_peer_by_transacid_connect, &pc_pkt->transac_id))) {
+ pc_pkt_req = pc_peer->p_pkt_connect;
+ // TCP: no timer
+ }
+ else if ((pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_self->p_list_peers, __pred_find_peer_by_transacid_connectionbind, &pc_pkt->transac_id))) {
+ pc_pkt_req = pc_peer->p_pkt_connbind;
+ // TCP: no timer
+ }
+ else if (p_self->p_pkt_refresh && tnet_stun_utils_transac_id_cmp(p_self->p_pkt_refresh->transac_id, pc_pkt->transac_id) == 0) {
+ pc_pkt_req = p_self->p_pkt_refresh;
+ CANCEL_TIMER(p_self, refresh);
+ }
+
+ if (!pc_pkt_req) {
+ TSK_DEBUG_INFO("No matching request[TID=%s]", pc_pkt->transac_id);
+ // Not an error as the "fd" could be shared by several processes (e.g. ICE)
+ goto bail;
+ }
+
+ /*** SUCCESS ***/
+ if (TNET_STUN_PKT_RESP_IS_SUCCESS(pc_pkt)) {
+ // --- ALLOC --- //
+ if (pc_pkt_req == p_self->p_pkt_alloc) {
+ const tnet_stun_attr_address_t *pc_attr_addr;
+ tnet_ip_t ip_addr;
+ const tnet_stun_attr_vdata_t *pc_attr_lifetime;
+ // XOR-MAPPED-ADDRESS (optional)
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_xor_mapped_address, (const tnet_stun_attr_t**)&pc_attr_addr)) == 0 && pc_attr_addr) {
+ if ((ret = tnet_stun_utils_inet_ntop((pc_attr_addr->e_family == tnet_stun_address_family_ipv6), &pc_attr_addr->address, &ip_addr)) == 0) {
+ p_self->b_srflx_ipv6 = (pc_attr_addr->e_family == tnet_stun_address_family_ipv6);
+ p_self->u_srflx_port = pc_attr_addr->u_port;
+ tsk_strupdate(&p_self->p_srflx_ip, ip_addr);
+ }
+ }
+ // LIFETIME (optional)
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_lifetime, (const tnet_stun_attr_t**)&pc_attr_lifetime)) == 0 && pc_attr_lifetime && pc_attr_lifetime->u_data_size == 4) {
+ p_self->u_lifetime_alloc_in_sec = TSK_TO_UINT32(pc_attr_lifetime->p_data_ptr);
+ }
+ // XOR-RELAYED-ADDRESS (required)
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_xor_relayed_address, (const tnet_stun_attr_t**)&pc_attr_addr))) {
+ _tnet_turn_session_raise_event_alloc_nok(p_self);
+ goto bail;
+ }
+ if (!pc_attr_addr) {
+ TSK_DEBUG_ERROR("XOR-RELAYED-ADDRESS missing in success response for Allocate");
+ ret = -4;
+ _tnet_turn_session_raise_event_alloc_nok(p_self);
+ goto bail;
+ }
+ if ((ret = tnet_stun_utils_inet_ntop((pc_attr_addr->e_family == tnet_stun_address_family_ipv6), &pc_attr_addr->address, &ip_addr))) {
+ _tnet_turn_session_raise_event_alloc_nok(p_self);
+ goto bail;
+ }
+
+ // Uncomment to test [TURN Client] <-> [Turn Server] <-> [Any Client]
+#if 0
+ {
+ struct sockaddr_storage to;
+ tnet_sockaddr_init(ip_addr, pc_attr_addr->u_port, p_self->p_lcl_sock->type, &to);
+ tnet_sockfd_sendto(p_self->p_lcl_sock->fd, (const struct sockaddr*)&to, "pinhole", 7); // open pinhole to allow incoming data
+ tnet_sockfd_sendto(p_self->p_lcl_sock->fd, (const struct sockaddr*)&to, "pinhole", 7); // open pinhole to allow incoming data
+ }
+#endif
+ // Schedule refresh
+ TNET_TURN_SESSION_TIMER_SCHEDULE_SEC(p_self, p_self->timer.u_timer_id_refresh, p_self->u_lifetime_alloc_in_sec);
+
+ p_self->e_alloc_state = tnet_stun_state_ok;
+ p_self->b_rel_ipv6 = (pc_attr_addr->e_family == tnet_stun_address_family_ipv6);
+ p_self->u_rel_port = pc_attr_addr->u_port;
+ tsk_strupdate(&p_self->p_rel_ip, ip_addr);
+
+ _tnet_turn_session_raise_event_alloc_ok(p_self);
+ }
+ // --- CREATE-PERMISSION --- //
+ else if (pc_pkt_req->e_type == tnet_stun_pkt_type_createpermission_request) {
+ TSK_DEBUG_INFO("TURN 'CREATE-PERMISSION' OK for peer-id = %ld", pc_peer->id);
+ pc_peer->e_createperm_state = tnet_stun_state_ok;
+ TNET_TURN_SESSION_TIMER_SCHEDULE_MILLIS(p_self, pc_peer->timer.fresh.createperm.id, pc_peer->timer.fresh.createperm.u_timeout);
+ _tnet_turn_session_raise_event_createperm_ok(p_self, pc_peer->id);
+ }
+ // --- CHANNEL-BIND --- //
+ else if (pc_pkt_req->e_type == tnet_stun_pkt_type_channelbind_request) {
+ TSK_DEBUG_INFO("TURN 'CHANNEL-BIND' OK for peer-id = %ld", pc_peer->id);
+ pc_peer->e_chanbind_state = tnet_stun_state_ok;
+ TNET_TURN_SESSION_TIMER_SCHEDULE_MILLIS(p_self, pc_peer->timer.fresh.chanbind.id, pc_peer->timer.fresh.chanbind.u_timeout);
+ _tnet_turn_session_raise_event_chanbind_ok(p_self, pc_peer->id);
+ }
+ // --- CONNECT --- //
+ else if (pc_pkt_req->e_type == tnet_stun_pkt_type_connect_request) {
+ TSK_DEBUG_INFO("TURN 'CONNECT' OK for peer-id = %ld", pc_peer->id);
+ if ((ret = _tnet_turn_session_process_success_connect_pkt(p_self, pc_peer, pc_pkt))) {
+ goto bail;
+ }
+ }
+ // --- CONNECTION-BIND --- //
+ else if (pc_pkt_req->e_type == tnet_stun_pkt_type_connectionbind_request) {
+ TSK_DEBUG_INFO("TURN 'CONNECTION-BIND' OK for peer-id = %ld", pc_peer->id);
+ pc_peer->e_connbind_state = tnet_stun_state_ok;
+ _tnet_turn_session_raise_event_connectionbind_ok(p_self, pc_peer->id);
+ }
+ // --- REFRESH --- //
+ else if (pc_pkt_req == p_self->p_pkt_refresh) {
+ const tnet_stun_attr_vdata_t *pc_attr_lifetime;
+ TSK_DEBUG_INFO("TURN 'REFRESH' OK for peer-id = %ld", pc_peer ? pc_peer->id : -1);
+ p_self->e_refresh_state = tnet_stun_state_ok;
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_lifetime, (const tnet_stun_attr_t**)&pc_attr_lifetime)) == 0 && pc_attr_lifetime && pc_attr_lifetime->u_data_size == 4) {
+ p_self->u_lifetime_alloc_in_sec = TSK_TO_UINT32(pc_attr_lifetime->p_data_ptr);
+ }
+ TNET_TURN_SESSION_TIMER_SCHEDULE_SEC(p_self, p_self->timer.u_timer_id_refresh, p_self->u_lifetime_alloc_in_sec);
+ _tnet_turn_session_raise_event_refresh_ok(p_self);
+ }
+ }
+ /*** ERROR ***/
+ else {
+ tsk_bool_t b_nok = tsk_true;
+ if ((ret = tnet_stun_pkt_get_errorcode(pc_pkt, &u_code))) {
+ goto bail;
+ }
+ if (u_code > 299) {
+ tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_error_code, (const tnet_stun_attr_t**)&pc_attr_err);
+ }
+ if (u_code == kStunErrCodeUnauthorized || u_code == kStunErrCodeStaleNonce) {
+ if (u_code == kStunErrCodeUnauthorized) {
+ // Make sure this is not an authentication failure (#2 401)
+ // Do not send another req to avoid endless messages
+ if ((tnet_stun_pkt_attr_exists(pc_pkt_req, tnet_stun_attr_type_message_integrity))) { // already has a MESSAGE-INTEGRITY?
+ TSK_DEBUG_ERROR("TURN authentication failed");
+ goto check_nok;
+ // INDICATION messages cannot receive 401 responses
+ }
+ }
+ if ((ret = tnet_stun_pkt_auth_prepare_2(pc_pkt_req, p_self->cred.p_usr_name, p_self->cred.p_pwd, pc_pkt))) {
+ goto check_nok;
+ }
+ if ((ret = _tnet_turn_session_send_pkt_0(p_self, pc_peer, pc_pkt_req)) == 0) {
+ b_nok = tsk_false; goto check_nok;
+ }
+ }
+ else if (u_code == kStunErrCodeUnknownAttributes) {
+ if((ret = _tnet_turn_session_process_err420_pkt(pc_pkt_req, pc_pkt))) {
+ goto check_nok;
+ }
+ if ((ret = _tnet_turn_session_send_pkt_0(p_self, pc_peer, pc_pkt_req)) == 0) {
+ b_nok = tsk_false; goto check_nok;
+ }
+ }
+
+check_nok:
+ if (b_nok) {
+ TSK_DEBUG_INFO("--- TURN response code = %hu, phrase = %s, peer-id=%ld, ---",
+ u_code, pc_attr_err ? pc_attr_err->p_reason_phrase : "null", pc_peer ? pc_peer->id : -1);
+ if (pc_pkt_req == p_self->p_pkt_alloc) {
+ p_self->e_alloc_state = tnet_stun_state_nok;
+ _tnet_turn_session_raise_event_alloc_nok(p_self);
+ }
+ else if (pc_pkt_req->e_type == tnet_stun_pkt_type_channelbind_request) {
+ pc_peer->e_chanbind_state = tnet_stun_state_nok;
+ _tnet_turn_session_raise_event_chanbind_nok(p_self, pc_peer->id);
+ }
+ else if (pc_pkt_req->e_type == tnet_stun_pkt_type_createpermission_request) {
+ pc_peer->e_createperm_state = tnet_stun_state_nok;
+ _tnet_turn_session_raise_event_createperm_nok(p_self, pc_peer->id);
+ }
+ else if (pc_pkt_req == p_self->p_pkt_refresh) {
+ p_self->e_refresh_state = tnet_stun_state_nok;
+ _tnet_turn_session_raise_event_refresh_nok(p_self);
+ }
+ }
+ }
+
+ break;
+ }
+ case tnet_stun_pkt_type_connectionattempt_indication:
+ {
+ // Indicates we already have an active connection
+ const tnet_stun_attr_address_t *pc_attr_xor_peer_addr;
+ tnet_turn_peer_t* pc_peer = tsk_null;
+ // XOR-PEER-ADDRESS
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_xor_peer_address, (const tnet_stun_attr_t**)&pc_attr_xor_peer_addr)) == 0 && pc_attr_xor_peer_addr) {
+ if ((ret = _tnet_turn_peer_find_by_xpeer(p_self->p_list_peers, pc_attr_xor_peer_addr, (const tnet_turn_peer_t**)&pc_peer)) == 0 && pc_peer) {
+ if ((ret = _tnet_turn_session_process_success_connect_pkt(p_self, pc_peer, pc_pkt))) {
+ goto bail;
+ }
+ }
+ }
+ break;
+ }
+ case tnet_stun_pkt_type_data_indication:
+ {
+ TSK_DEBUG_ERROR("Unexpected code called"); // --> DATA-INDICATION must be handled in net-event
+ break;
+ }
+ default:
+ {
+ goto bail;
+ }
+ }
+
+ *pb_processed = tsk_true;
+
+bail:
+ // unlock()
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+// "pc_pkt" could be "200 response" or "CONNECTATTEMP-INDICATION"
+int _tnet_turn_session_process_success_connect_pkt(struct tnet_turn_session_s* p_self, tnet_turn_peer_t* pc_peer, const tnet_turn_pkt_t *pc_pkt)
+{
+ int ret = 0;
+ const tnet_stun_attr_vdata_t *pc_attr_connection_id;
+
+ if (!p_self || !pc_peer || !pc_pkt) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (pc_pkt->e_type != tnet_stun_pkt_type_connectionattempt_indication && !TNET_STUN_PKT_RESP_IS_SUCCESS(pc_pkt)) {
+ TSK_DEBUG_ERROR("Invalid packet type");
+ ret = -2;
+ goto bail;
+ }
+
+ // lock()
+ tsk_safeobj_lock(p_self);
+
+ if ((ret = tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_connection_id, (const tnet_stun_attr_t**)&pc_attr_connection_id)) == 0 && pc_attr_connection_id && pc_attr_connection_id->u_data_size == 4) {
+ pc_peer->u_conn_id = TSK_TO_UINT32(pc_attr_connection_id->p_data_ptr);
+ pc_peer->e_connect_state = tnet_stun_state_ok;
+ _tnet_turn_session_raise_event_connect_ok(p_self, pc_peer->id);
+ // Connect to the server and send "ConnectionBind" request using the "CONNECTION-ID" once connection is completed
+ pc_peer->conn_fd = tnet_transport_connectto(p_self->p_transport, p_self->p_srv_host, p_self->u_srv_port, p_self->p_transport->type);
+ if (pc_peer->conn_fd == TNET_INVALID_FD) {
+ TSK_DEBUG_ERROR("Failed to connect to %s:%d", p_self->p_srv_host, p_self->u_srv_port);
+ ret = -3;
+ goto bail;
+ }
+ }
+
+bail:
+ tsk_safeobj_unlock(p_self);
+ return ret;
+}
+
+static int _tnet_turn_session_transport_layer_dgram_cb(const tnet_transport_event_t* e)
+{
+ return _tnet_turn_session_transport_layer_process_cb(e);
+}
+
+static int _tnet_turn_session_transport_layer_stream_cb(const tnet_transport_event_t* e)
+{
+ return _tnet_turn_session_transport_layer_process_cb(e);
+}
+
+static int _tnet_turn_session_transport_layer_process_cb(const tnet_transport_event_t* e)
+{
+ tnet_turn_session_t* p_ss = (tnet_turn_session_t*)e->callback_data;
+ int ret = 0;
+ tnet_turn_pkt_t* p_pkt = tsk_null;
+ tsk_buffer_t* p_stream_buff_in = tsk_null;
+ const void* pc_data = tsk_null;
+ tsk_size_t u_data_size = 0;
+ tsk_bool_t b_stream = tsk_false, b_stream_appended = tsk_false, b_pkt_is_complete = tsk_false, b_got_msg= tsk_false;
+ tnet_turn_peer_t* pc_peer = tsk_null;
+ switch(e->type){
+ case event_data:
+ break;
+ case event_brokenpipe:
+ tsk_safeobj_lock(p_ss);
+ if (p_ss->p_lcl_sock && e->local_fd == p_ss->p_lcl_sock->fd) {
+ tnet_fd_t broken_fd = e->local_fd;
+ tsk_bool_t registered_fd = !!tnet_transport_have_socket(p_ss->p_transport, broken_fd);
+ if (registered_fd) {
+ tnet_transport_remove_socket(p_ss->p_transport, &broken_fd);
+ }
+ if (tnet_socket_handle_brokenpipe(p_ss->p_lcl_sock) == 0) {
+ if (registered_fd) {
+ tnet_transport_add_socket(p_ss->p_transport, p_ss->p_lcl_sock->fd, p_ss->p_lcl_sock->type, tsk_false/* do not take ownership */, tsk_true/* only Meaningful for tls*/, tsk_null);
+ }
+ }
+ }
+ tsk_safeobj_unlock(p_ss);
+ return 0;
+ case event_connected:
+ if (p_ss->p_lcl_sock && p_ss->p_lcl_sock->fd == e->local_fd) {
+ tsk_safeobj_lock(p_ss);
+ p_ss->b_stream_connected = tsk_true;
+ if (p_ss->p_stream_buff_out && p_ss->p_stream_buff_out->size > 0) {
+ TSK_DEBUG_INFO("Sending %u TURN pending bytes", (unsigned)p_ss->p_stream_buff_out->size);
+ _tnet_turn_session_send_buff(p_ss, p_ss->p_stream_buff_out->data, (uint16_t)p_ss->p_stream_buff_out->size);
+ TSK_OBJECT_SAFE_FREE(p_ss->p_stream_buff_out);
+ }
+ tsk_safeobj_unlock(p_ss);
+ }
+ else {
+ tsk_safeobj_lock(p_ss);
+ pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_ss->p_list_peers, __pred_find_peer_by_fd, &e->local_fd);
+ if (pc_peer) {
+ pc_peer->b_stream_connected = tsk_true;
+ // Send ConnectionBind
+ if ((ret = _tnet_turn_session_send_connbind(p_ss, pc_peer))) {
+ goto bail;
+ }
+ }
+ tsk_safeobj_unlock(p_ss);
+ }
+ return 0;
+ case event_error:
+ case event_closed:
+ case event_removed:
+ /* case event_removed: */
+ if (p_ss->p_lcl_sock && p_ss->p_lcl_sock->fd == e->local_fd) {
+ tsk_safeobj_lock(p_ss);
+ p_ss->b_stream_connected = tsk_false;
+ p_ss->b_stream_error = (e->type == event_error);
+ TSK_OBJECT_SAFE_FREE(p_ss->p_stream_buff_out);
+ tsk_safeobj_unlock(p_ss);
+ }
+ else {
+ tsk_safeobj_lock(p_ss);
+ pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_ss->p_list_peers, __pred_find_peer_by_fd, &e->local_fd);
+ if (pc_peer) {
+ pc_peer->b_stream_connected = tsk_false;
+ pc_peer->conn_fd = TNET_INVALID_FD;
+ }
+ tsk_safeobj_unlock(p_ss);
+ }
+ return 0;
+ default:
+ return 0;
+ }
+
+ /*** If the code reach this line it means we have to deal with a "NET-DATA-EVENT" ***/
+
+ p_ss->cb.e.pc_enet = e;
+ pc_data = e->data;
+ u_data_size = e->size;
+ b_stream = TNET_SOCKET_TYPE_IS_STREAM(p_ss->p_lcl_sock->type);
+ b_stream_appended = tsk_false;
+
+handle_data:
+ b_got_msg = tsk_false;
+
+ // TODO: /!\
+ // - When the requested transport is TCP/TLS then we will receive RAW data on the connected peer socket which means no way to guess the end-of-the message
+ // - No issue for when requested transport is UDP because we'll always have the data encapsulated in CHANNEL-DATA or DATA-INDICATION.
+ if (b_stream) {
+ if (!b_stream_appended) {
+ tsk_safeobj_lock(p_ss);
+ pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_ss->p_list_peers, __pred_find_peer_by_fd, &e->local_fd);
+ if (pc_peer) {
+ p_stream_buff_in = tsk_object_ref(pc_peer->p_stream_buff_in);
+ }
+ else {
+ p_stream_buff_in = tsk_object_ref(p_ss->p_stream_buff_in);
+ }
+ tsk_safeobj_unlock(p_ss);
+
+ if ((ret = tsk_buffer_append(p_stream_buff_in, e->data, e->size))) {
+ goto bail;
+ }
+ b_stream_appended = tsk_true;
+ }
+ // Guard
+ if (p_stream_buff_in->size > kTurnStreamChunckMaxSize) {
+ TSK_DEBUG_ERROR("Too much data in the stream buffer: %u", (unsigned)p_stream_buff_in->size);
+ tsk_buffer_cleanup(p_stream_buff_in);
+ goto bail;
+ }
+ pc_data = p_stream_buff_in->data;
+ u_data_size = p_stream_buff_in->size;
+ }
+
+ if (!TNET_STUN_BUFF_IS_STUN2(((const uint8_t*)pc_data), u_data_size)) {
+ // ChannelData ?
+ if (TNET_STUN_BUFF_IS_CHANNEL_DATA(((const uint8_t*)pc_data), u_data_size)) {
+ const uint8_t* _p_data = (const uint8_t*)pc_data;
+ // Channel Number in [0x4000 - 0x7FFF]
+ // rfc5766 - 11.6. Receiving a ChannelData Message
+ // rfc5766 - 11.4. The ChannelData Message
+ // If the message uses a value in the reserved range (0x8000 through 0xFFFF), then the message is silently discarded
+ static const tsk_size_t kChannelDataHdrSize = 4; // Channel Number(2 bytes) + Length (2 bytes)
+ uint16_t u_chan_num = tnet_ntohs_2(&_p_data[0]);
+ if ((pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_ss->p_list_peers, __pred_find_peer_by_channum, &u_chan_num))) {
+ uint16_t u_len = tnet_ntohs_2(&_p_data[2]);
+ if (u_len <= (u_data_size - kChannelDataHdrSize)) {
+ b_got_msg = tsk_true;
+ _tnet_turn_session_raise_event_recv_data(p_ss, pc_peer->id, &_p_data[kChannelDataHdrSize], u_len);
+ if (p_stream_buff_in) {
+ /* The padding is not reflected in the length
+ field of the ChannelData message, so the actual size of a ChannelData
+ message (including padding) is (4 + Length) rounded up to the nearest
+ multiple of 4. Over UDP, the padding is not required but MAY be
+ included.
+ */
+ tsk_size_t u_pad_len = (u_len & 3) ? (4 - (u_len & 3)) : 0;
+ tsk_buffer_remove(p_stream_buff_in, 0, kChannelDataHdrSize + u_len + u_pad_len);
+ }
+ }
+ else {
+ TSK_DEBUG_INFO("TURN channel data too short");
+ }
+ }
+ goto bail;
+ } // if (TNET_STUN_BUFF_IS_CHANNEL_DATA...
+
+ // Must never happen: Data must be received via CHANNEL-DATA or DATA-INDICATION
+ TSK_DEBUG_INFO("Calling unexpected code :(");
+
+ if (b_stream) {
+ tsk_safeobj_lock(p_ss);
+ pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_ss->p_list_peers, __pred_find_peer_by_fd, &e->local_fd);
+ tsk_safeobj_unlock(p_ss);
+ }
+ _tnet_turn_session_raise_event_recv_data(p_ss, pc_peer ? pc_peer->id : kTurnPeerIdInvalid, pc_data, u_data_size);
+ if (p_stream_buff_in) {
+ tsk_buffer_cleanup(p_stream_buff_in);
+ }
+ goto bail;
+ } // if (!TNET_STUN_BUFF_IS_STUN2...
+
+ /*** At this step it means we have a STUN packet in the buffer ***/
+
+ // Make sure we have a complete packet in the buffer
+ if (b_stream) {
+ if ((ret = tnet_stun_pkt_is_complete(pc_data, u_data_size, &b_pkt_is_complete))) {
+ goto bail;
+ }
+ if (!b_pkt_is_complete) {
+ TSK_DEBUG_INFO("The stream length is too short to contains a complete STUN/TURN packet");
+ goto bail;
+ }
+ }
+
+ // Parse the packet
+ if ((ret = tnet_stun_pkt_read(pc_data, u_data_size, &p_pkt))) {
+ goto bail;
+ }
+
+ // Remove the parsed data
+ if (p_stream_buff_in && p_pkt) {
+ tsk_size_t u_pad_len = (p_pkt->u_length & 3) ? (4 - (p_pkt->u_length & 3)) : 0;
+ tsk_buffer_remove(p_stream_buff_in, 0, kStunPktHdrSizeInOctets + p_pkt->u_length + u_pad_len);
+ }
+
+ if (p_pkt) {
+ b_got_msg = tsk_true;
+ if (p_pkt->e_type == tnet_stun_pkt_type_data_indication) {
+ const tnet_stun_attr_vdata_t *pc_attr_data;
+ const tnet_stun_attr_address_t *pc_attr_xpeer;
+ const tnet_turn_peer_t *pc_peer;
+ // XOR-PEER-ADDRESS (required)
+ if ((ret = tnet_stun_pkt_attr_find_first(p_pkt, tnet_stun_attr_type_xor_peer_address, (const tnet_stun_attr_t**)&pc_attr_xpeer)) || !pc_attr_xpeer) {
+ TSK_DEBUG_ERROR("XOR-PEER-ADDRESS missing in DATA-INDICATION");
+ ret = -4;
+ goto bail;
+ }
+ tsk_safeobj_lock(p_ss); // lock to make sure the list will not be modified
+ if ((ret = _tnet_turn_peer_find_by_xpeer(p_ss->p_list_peers, pc_attr_xpeer, &pc_peer))) {
+ tsk_safeobj_unlock(p_ss);
+ goto bail;
+ }
+ tsk_safeobj_unlock(p_ss); // unlock()
+ // DATA (required)
+ if ((ret = tnet_stun_pkt_attr_find_first(p_pkt, tnet_stun_attr_type_data, (const tnet_stun_attr_t**)&pc_attr_data)) || !pc_attr_data) {
+ TSK_DEBUG_ERROR("DATA missing in DATA-INDICAION");
+ ret = -4;
+ goto bail;
+ }
+
+ _tnet_turn_session_raise_event_recv_data(p_ss, pc_peer ? pc_peer->id : kTurnPeerIdInvalid, pc_attr_data->p_data_ptr, pc_attr_data->u_data_size);
+ }
+ else {
+ tsk_bool_t b_processed;
+ if ((ret = _tnet_turn_session_process_incoming_pkt(p_ss, p_pkt, &b_processed))) {
+ goto bail;
+ }
+ if (!b_processed) {
+ const tnet_turn_peer_t *pc_peer;
+ tsk_safeobj_lock(p_ss);
+ pc_peer = (const tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_ss->p_list_peers, __pred_find_peer_by_fd, &e->local_fd);
+ tsk_safeobj_unlock(p_ss); // unlock()
+ // Forward to listeners (e.g. ICE context)
+ _tnet_turn_session_raise_event_recv_data(p_ss, pc_peer ? pc_peer->id : kTurnPeerIdInvalid, pc_data, u_data_size);
+ }
+ }
+ }
+
+bail:
+ // Handle next message in the stream buffer
+ if (ret == 0 && b_got_msg && b_stream && p_stream_buff_in && p_stream_buff_in->size > 0) {
+ goto handle_data;
+ }
+
+ TSK_OBJECT_SAFE_FREE(p_pkt);
+ TSK_OBJECT_SAFE_FREE(p_stream_buff_in);
+ p_ss->cb.e.pc_enet = tsk_null;
+ return ret;
+}
+
+static int _tnet_turn_session_timer_callback(const void* pc_arg, tsk_timer_id_t timer_id)
+{
+#undef _tnet_turn_session_raise_event_alloc_ok
+#define _tnet_turn_session_raise_event_alloc_ok(_self, _u_peer_id) _tnet_turn_session_raise_event0((_self), tnet_turn_session_event_type_alloc_ok, kTurnPeerIdInvalid)
+#undef _tnet_turn_session_raise_event_alloc_nok
+#define _tnet_turn_session_raise_event_alloc_nok(_self, _u_peer_id) _tnet_turn_session_raise_event0((_self), tnet_turn_session_event_type_alloc_nok, kTurnPeerIdInvalid)
+#undef _tnet_turn_session_raise_event_refresh_ok
+#define _tnet_turn_session_raise_event_refresh_ok(_self, _u_peer_id) _tnet_turn_session_raise_event0((_self), tnet_turn_session_event_type_refresh_ok, kTurnPeerIdInvalid)
+#undef _tnet_turn_session_raise_event_refresh_nok
+#define _tnet_turn_session_raise_event_refresh_nok(_self, _u_peer_id) _tnet_turn_session_raise_event0((_self), tnet_turn_session_event_type_refresh_nok, kTurnPeerIdInvalid)
+#define RETRANSMIT(parent, which, u_peer_id) \
+ parent->timer.rtt.which.u_timeout <<= 1; \
+ if (parent->timer.rtt.which.u_timeout <= kStunUdpRetransmitTimoutMaxInMs) { \
+ if ((ret = _tnet_turn_session_send_pkt(p_ss, parent->p_pkt_##which))) { \
+ parent->e_##which##_state = tnet_stun_state_nok; \
+ _tnet_turn_session_raise_event_##which##_nok(p_ss, u_peer_id); \
+ goto bail; \
+ } \
+ parent->timer.rtt.which.id = tsk_timer_manager_schedule(p_ss->timer.p_mgr, parent->timer.rtt.which.u_timeout, _tnet_turn_session_timer_callback, p_ss); \
+ } else { \
+ _tnet_turn_session_raise_event_##which##_nok(p_ss, u_peer_id); \
+ }
+
+ tnet_turn_session_t* p_ss = (tnet_turn_session_t*)pc_arg;
+ tnet_turn_peer_t* pc_peer;
+ int ret = 0;
+ tsk_safeobj_lock(p_ss); // must
+ if (p_ss->timer.rtt.alloc.id == timer_id) {
+ RETRANSMIT(p_ss, alloc, kTurnPeerIdInvalid);
+ }
+ else if ((pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_ss->p_list_peers, __pred_find_peer_by_timer_rtt_chanbind, &timer_id))) {
+ RETRANSMIT(pc_peer, chanbind, pc_peer->id);
+ }
+ else if ((pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_ss->p_list_peers, __pred_find_peer_by_timer_rtt_createperm, &timer_id))) {
+ RETRANSMIT(pc_peer, createperm, pc_peer->id);
+ }
+ else if (p_ss->timer.rtt.refresh.id == timer_id) {
+ RETRANSMIT(p_ss, refresh, kTurnPeerIdInvalid);
+ }
+ else if (p_ss->timer.u_timer_id_refresh == timer_id) {
+ if ((ret = _tnet_turn_session_send_refresh(p_ss))) {
+ goto bail;
+ }
+ }
+ else if ((pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_ss->p_list_peers, __pred_find_peer_by_timer_fresh_chanbind, &timer_id))) {
+ if ((ret = tnet_turn_session_chanbind(p_ss, pc_peer->id))) {
+ goto bail;
+ }
+ }
+ else if ((pc_peer = (tnet_turn_peer_t*)tsk_list_find_object_by_pred(p_ss->p_list_peers, __pred_find_peer_by_timer_fresh_createperm, &timer_id))) {
+ if ((ret = _tnet_turn_session_send_permission(p_ss, pc_peer))) {
+ goto bail;
+ }
+ }
+
+bail:
+ tsk_safeobj_unlock(p_ss);
+ return ret;
+}
+
+static int _tnet_turn_peer_create(const char* pc_peer_ip, uint16_t u_peer_port, tsk_bool_t b_ipv6, struct tnet_turn_peer_s **pp_peer)
+{
+ extern const tsk_object_def_t *tnet_turn_peer_def_t;
+ static tnet_turn_peer_id_t __l_peer_id = 0;
+ tnet_stun_addr_t peer_addr;
+ int ret;
+ if (!pc_peer_ip || !u_peer_port || !pp_peer) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = tnet_stun_utils_inet_pton(b_ipv6, pc_peer_ip, &peer_addr))) {
+ TSK_DEBUG_ERROR("inet_pton(%s,IPv6=%d) failed", pc_peer_ip, b_ipv6);
+ goto bail;
+ }
+ if (!(*pp_peer = tsk_object_new(tnet_turn_peer_def_t))) {
+ TSK_DEBUG_ERROR("Failed to create TURN peer object");
+ return -2;
+ }
+ (*pp_peer)->p_addr_ip = tsk_strdup(pc_peer_ip);
+ memcpy((*pp_peer)->addr_ip, peer_addr, sizeof(peer_addr));
+ (*pp_peer)->u_addr_port = u_peer_port;
+ (*pp_peer)->b_ipv6 = b_ipv6;
+ tsk_atomic_inc(&__l_peer_id);
+ (*pp_peer)->id = __l_peer_id;
+ (*pp_peer)->timer.rtt.chanbind.id = TSK_INVALID_TIMER_ID;
+ (*pp_peer)->timer.rtt.createperm.id = TSK_INVALID_TIMER_ID;
+ (*pp_peer)->timer.rtt.chanbind.u_timeout = kStunUdpRetransmitTimoutMinInMs;
+ (*pp_peer)->timer.rtt.createperm.u_timeout = kStunUdpRetransmitTimoutMinInMs;
+ (*pp_peer)->timer.fresh.chanbind.id = TSK_INVALID_TIMER_ID;
+ (*pp_peer)->timer.fresh.createperm.id = TSK_INVALID_TIMER_ID;
+ (*pp_peer)->timer.fresh.chanbind.u_timeout = kTurnChannelBindingTimeOutInSec * 1000;
+ (*pp_peer)->timer.fresh.createperm.u_timeout = kTurnPermissionTimeOutInSec * 1000;
+ (*pp_peer)->e_chanbind_state = tnet_stun_state_none;
+ (*pp_peer)->e_createperm_state = tnet_stun_state_none;
+
+bail:
+ return ret;
+}
+
+static int _tnet_turn_peer_find_by_xpeer(const tnet_turn_peers_L_t* pc_peers, const tnet_stun_attr_address_t* pc_xpeer, const tnet_turn_peer_t **ppc_peer)
+{
+ const tsk_list_item_t *pc_item;
+ const tnet_turn_peer_t *pc_peer;
+ if (!pc_peers || !pc_xpeer || !ppc_peer) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *ppc_peer = tsk_null;
+ tsk_list_foreach(pc_item, pc_peers) {
+ pc_peer = (const tnet_turn_peer_t *)pc_item->data;
+ if (pc_peer->u_addr_port == pc_xpeer->u_port) {
+ if (tnet_stun_utils_buff_cmp(
+ pc_peer->addr_ip, pc_peer->b_ipv6 ? 16 : 4,
+ pc_xpeer->address, (pc_xpeer->e_family == tnet_stun_address_family_ipv6) ? 16 : 4) == 0) {
+ *ppc_peer = pc_peer;
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+static tsk_object_t* tnet_turn_session_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_session_t *p_ss = (tnet_turn_session_t *)self;
+ if (p_ss) {
+ tsk_safeobj_init(p_ss);
+ }
+ return self;
+}
+static tsk_object_t* tnet_turn_session_dtor(tsk_object_t * self)
+{
+ tnet_turn_session_t *p_ss = (tnet_turn_session_t *)self;
+ if (p_ss) {
+ // stop()
+ tnet_turn_session_stop(p_ss);
+ // timer.free()
+ TSK_OBJECT_SAFE_FREE(p_ss->timer.p_mgr);
+ // cred.free()
+ TSK_FREE(p_ss->cred.p_usr_name);
+ TSK_FREE(p_ss->cred.p_pwd);
+ // others.free()
+ TSK_OBJECT_SAFE_FREE(p_ss->p_pkt_alloc);
+ TSK_OBJECT_SAFE_FREE(p_ss->p_pkt_refresh);
+ TSK_OBJECT_SAFE_FREE(p_ss->p_lcl_sock);
+
+ TSK_FREE(p_ss->p_buff_chandata_ptr);
+ TSK_FREE(p_ss->p_buff_send_ptr);
+ TSK_FREE(p_ss->p_rel_ip);
+ TSK_FREE(p_ss->p_srflx_ip);
+ TSK_FREE(p_ss->p_srv_host);
+
+ if (p_ss->p_transport) {
+ tnet_transport_shutdown(p_ss->p_transport);
+ TSK_OBJECT_SAFE_FREE(p_ss->p_transport);
+ }
+
+ TSK_OBJECT_SAFE_FREE(p_ss->p_list_peers);
+ TSK_OBJECT_SAFE_FREE(p_ss->p_stream_buff_in);
+ TSK_OBJECT_SAFE_FREE(p_ss->p_stream_buff_out);
+
+ TSK_OBJECT_SAFE_FREE(p_ss->proxy.info);
+
+ TSK_FREE(p_ss->ssl.path_priv);
+ TSK_FREE(p_ss->ssl.path_pub);
+ TSK_FREE(p_ss->ssl.path_ca);
+
+ tsk_safeobj_deinit(p_ss);
+ TSK_DEBUG_INFO("*** TURN Session destroyed ***");
+ }
+ return self;
+}
+static int tnet_turn_session_cmp(const tsk_object_t *_ss1, const tsk_object_t *_ss2)
+{
+ const tnet_turn_session_t *pc_ss1 = (const tnet_turn_session_t *)_ss1;
+ const tnet_turn_session_t *pc_ss2 = (const tnet_turn_session_t *)_ss2;
+
+ return (int)(pc_ss1 - pc_ss2);
+}
+static const tsk_object_def_t tnet_turn_session_def_s = {
+ sizeof(tnet_turn_session_t),
+ tnet_turn_session_ctor,
+ tnet_turn_session_dtor,
+ tnet_turn_session_cmp,
+};
+const tsk_object_def_t *tnet_turn_session_def_t = &tnet_turn_session_def_s;
+
+
+static tsk_object_t* tnet_turn_peer_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_peer_t *p_peer = (tnet_turn_peer_t *)self;
+ if (p_peer) {
+
+ }
+ return self;
+}
+static tsk_object_t* tnet_turn_peer_dtor(tsk_object_t * self)
+{
+ tnet_turn_peer_t *p_peer = (tnet_turn_peer_t *)self;
+ if (p_peer) {
+ TSK_FREE(p_peer->p_addr_ip);
+ TSK_OBJECT_SAFE_FREE(p_peer->p_pkt_chanbind);
+ TSK_OBJECT_SAFE_FREE(p_peer->p_pkt_createperm);
+ TSK_OBJECT_SAFE_FREE(p_peer->p_pkt_sendind);
+ TSK_OBJECT_SAFE_FREE(p_peer->p_pkt_connect);
+ TSK_OBJECT_SAFE_FREE(p_peer->p_pkt_connbind);
+ TSK_OBJECT_SAFE_FREE(p_peer->p_stream_buff_in);
+ TSK_OBJECT_SAFE_FREE(p_peer->p_stream_buff_out);
+#if PRINT_DESTROYED_MSG || 1
+ TSK_DEBUG_INFO("*** TURN peer destroyed ***");
+#endif
+ }
+ return self;
+}
+static const tsk_object_def_t tnet_turn_peer_def_s = {
+ sizeof(tnet_turn_peer_t),
+ tnet_turn_peer_ctor,
+ tnet_turn_peer_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_peer_def_t = &tnet_turn_peer_def_s;
diff --git a/tinyNET/src/turn/tnet_turn_session.h b/tinyNET/src/turn/tnet_turn_session.h
new file mode 100644
index 0000000..fa4a030
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_session.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TURN_SESSION_H
+#define TNET_TURN_SESSION_H
+
+#include "tinynet_config.h"
+#include "stun/tnet_stun_types.h"
+#include "tnet_types.h"
+
+#include "tsk_common.h" /* tsk_bool_t */
+
+TNET_BEGIN_DECLS
+
+struct tnet_turn_session_s;
+struct tnet_socket_s;
+struct tnet_proxyinfo_s;
+enum tnet_socket_type_e;
+#define kTurnPeerIdInvalid -1
+
+typedef enum tnet_turn_session_event_type_e
+{
+ tnet_turn_session_event_type_alloc_ok,
+ tnet_turn_session_event_type_alloc_nok,
+ tnet_turn_session_event_type_refresh_ok,
+ tnet_turn_session_event_type_refresh_nok,
+ tnet_turn_session_event_type_perm_ok,
+ tnet_turn_session_event_type_perm_nok,
+ tnet_turn_session_event_type_recv_data,
+ tnet_turn_session_event_type_chanbind_ok,
+ tnet_turn_session_event_type_chanbind_nok,
+ tnet_turn_session_event_type_connect_ok,
+ tnet_turn_session_event_type_connect_nok,
+ tnet_turn_session_event_type_connectionbind_ok,
+ tnet_turn_session_event_type_connectionbind_nok,
+}
+tnet_turn_session_event_type_t;
+
+typedef struct tnet_turn_session_event_xs {
+ enum tnet_turn_session_event_type_e e_type;
+ tnet_turn_peer_id_t u_peer_id;
+ const void* pc_usr_data;
+ const struct tnet_transport_event_s* pc_enet;
+ struct tnet_turn_session_s* pc_session;
+ struct {
+ const void* pc_data_ptr;
+ tsk_size_t u_data_size;
+ } data;
+} tnet_turn_session_event_xt;
+
+typedef int (*tnet_turn_session_callback_f)(const struct tnet_turn_session_event_xs *e);
+
+TINYNET_API int tnet_turn_session_create(struct tnet_socket_s* p_lcl_sock, enum tnet_turn_transport_e e_req_transport, const char* pc_srv_host, uint16_t u_srv_port, struct tnet_turn_session_s** pp_self);
+TINYNET_API int tnet_turn_session_create_2(const char* pc_lcl_ip, uint16_t u_lcl_port, enum tnet_socket_type_e e_lcl_type, enum tnet_turn_transport_e e_req_transport, const char* pc_srv_host, uint16_t u_srv_port, struct tnet_turn_session_s** pp_self);
+TINYNET_API int tnet_turn_session_create_4(struct tnet_socket_s* p_lcl_sock, enum tnet_turn_transport_e e_req_transport, const char* pc_srv_host, uint16_t u_srv_port, enum tnet_socket_type_e e_srv_type, struct tnet_turn_session_s** pp_self);
+#define tnet_turn_session_create_3(e_lcl_type, e_req_transport, pc_srv_host, u_srv_port, pp_self) tnet_turn_session_create_2(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, (e_lcl_type), (e_req_transport), (pc_srv_host), (u_srv_port), (pp_self))
+#define tnet_turn_session_create_udp_ipv4(e_req_transport, pc_srv_host, u_srv_port, pp_self) tnet_turn_session_create_3(tnet_socket_type_udp_ipv4, e_req_transport, pc_srv_host, u_srv_port, pp_self)
+#define tnet_turn_session_create_udp_ipv6(pc_srv_host, u_srv_port, pp_self) tnet_turn_session_create_3(tnet_socket_type_udp_ipv6, pc_srv_host, u_srv_port, pp_self)
+#define tnet_turn_session_create_udp_ipv46(e_req_transport, pc_srv_host, u_srv_port, pp_self) tnet_turn_session_create_3(tnet_socket_type_udp_ipv46, e_req_transport, pc_srv_host, u_srv_port, pp_self)
+TINYNET_API int tnet_turn_session_set_cred(struct tnet_turn_session_s* p_self, const char* pc_usr_name, const char* pc_pwd);
+TINYNET_API int tnet_turn_session_set_callback(struct tnet_turn_session_s* p_self, tnet_turn_session_callback_f f_fun, const void* pc_usr_data);
+TINYNET_API int tnet_turn_session_set_ssl_certs(struct tnet_turn_session_s* p_self, const char* path_priv, const char* path_pub, const char* path_ca, tsk_bool_t verify);
+TINYNET_API int tnet_turn_session_set_proxy_auto_detect(struct tnet_turn_session_s* p_self, tsk_bool_t auto_detect);
+TINYNET_API int tnet_turn_session_set_proxy_info(struct tnet_turn_session_s* p_self, struct tnet_proxyinfo_s* info);
+TINYNET_API int tnet_turn_session_prepare(struct tnet_turn_session_s* p_self);
+TINYNET_API int tnet_turn_session_start(struct tnet_turn_session_s* p_self);
+TINYNET_API int tnet_turn_session_allocate(struct tnet_turn_session_s* p_self);
+TINYNET_API int tnet_turn_session_get_relayed_addr(const struct tnet_turn_session_s* p_self, char** pp_ip, uint16_t *pu_port, tsk_bool_t *pb_ipv6);
+TINYNET_API int tnet_turn_session_get_srflx_addr(const struct tnet_turn_session_s* p_self, char** pp_ip, uint16_t *pu_port, tsk_bool_t *pb_ipv6);
+TINYNET_API int tnet_turn_session_get_state_alloc(const struct tnet_turn_session_s* pc_self, enum tnet_stun_state_e *pe_state);
+TINYNET_API int tnet_turn_session_get_socket_local(struct tnet_turn_session_s* p_self, struct tnet_socket_s** pp_lcl_sock);
+TINYNET_API int tnet_turn_session_get_state_createperm(const struct tnet_turn_session_s* pc_self, tnet_turn_peer_id_t u_peer_id, enum tnet_stun_state_e *pe_state);
+TINYNET_API int tnet_turn_session_get_state_connbind(const struct tnet_turn_session_s* pc_self, tnet_turn_peer_id_t u_peer_id, enum tnet_stun_state_e *pe_state);
+TINYNET_API int tnet_turn_session_get_req_transport(const struct tnet_turn_session_s* pc_self, enum tnet_turn_transport_e *pe_transport);
+TINYNET_API int tnet_turn_session_get_bytes_count(const struct tnet_turn_session_s* pc_self, uint64_t* bytes_in, uint64_t* bytes_out);
+TINYNET_API int tnet_turn_session_createpermission(struct tnet_turn_session_s* p_self, const char* pc_peer_addr, uint16_t u_peer_port, tnet_turn_peer_id_t* pu_peer_id);
+TINYNET_API int tnet_turn_session_deletepermission(struct tnet_turn_session_s* p_self, tnet_turn_peer_id_t u_peer_id);
+TINYNET_API int tnet_turn_session_chanbind(struct tnet_turn_session_s* p_self, tnet_turn_peer_id_t u_peer_id);
+TINYNET_API int tnet_turn_session_connect(struct tnet_turn_session_s* p_self, tnet_turn_peer_id_t u_peer_id);
+TINYNET_API int tnet_turn_session_send_data(struct tnet_turn_session_s* p_self, tnet_turn_peer_id_t u_peer_id, const void* pc_data_ptr, uint16_t u_data_size);
+TINYNET_API int tnet_turn_session_is_active(const struct tnet_turn_session_s* pc_self, tnet_turn_peer_id_t u_peer_id, tsk_bool_t *pb_active);
+TINYNET_API int tnet_turn_session_is_stream(const struct tnet_turn_session_s* pc_self, tsk_bool_t *pb_stream);
+TINYNET_API int tnet_turn_session_is_stream_connected(const struct tnet_turn_session_s* pc_self, tnet_turn_peer_id_t u_peer_id, tsk_bool_t *pb_connected);
+TINYNET_API int tnet_turn_session_stop(struct tnet_turn_session_s* p_self);
+
+TNET_END_DECLS
+
+#endif /* TNET_TURN_SESSION_H */
diff --git a/tinyNET/test/droid-makefile b/tinyNET/test/droid-makefile
new file mode 100644
index 0000000..0273af6
--- /dev/null
+++ b/tinyNET/test/droid-makefile
@@ -0,0 +1,28 @@
+APP := test
+
+CFLAGS := $(CFLAGS_COMMON) -I../src -I../../tinySAK/src
+LDFLAGS := $(LDFLAGS_COMMON) -Wl,-Bsymbolic,--whole-archive -l$(PROJECT) -ltinySAK -Wl,--entry=main
+
+all: $(APP)
+
+OBJS += $(APP).o
+
+$(APP): $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $^
+
+%.o: %.c
+ $(CC) -c $(INCLUDE) $(CFLAGS) $< -o $@
+
+install: $(APP)
+ $(ANDROID_SDK_ROOT)/tools/adb push $(APP) $(EXEC_DIR)/$(APP)
+ $(ANDROID_SDK_ROOT)/tools/adb shell chmod 777 $(EXEC_DIR)/$(APP)
+
+run:
+ $(ANDROID_SDK_ROOT)/tools/adb shell $(EXEC_DIR)/$(APP)
+
+#dbg:
+# $(MAKE) $(MAKEFILE) DEBUG="-g -DDEBUG"
+# $(MAKE) $(MAKEFILE) install
+
+clean:
+ @rm -f $(OBJS) $(APP) \ No newline at end of file
diff --git a/tinyNET/test/stdafx.c b/tinyNET/test/stdafx.c
new file mode 100644
index 0000000..4cac236
--- /dev/null
+++ b/tinyNET/test/stdafx.c
@@ -0,0 +1,23 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/tinyNET/test/stdafx.h b/tinyNET/test/stdafx.h
new file mode 100644
index 0000000..92f1061
--- /dev/null
+++ b/tinyNET/test/stdafx.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+
+#ifndef TEST_TNET_STDAFX_H
+#define TEST_TNET_STDAFX_H
+
+#ifdef WIN32
+#include "targetver.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+//#include <tchar.h>
+
+
+
+// TODO: reference additional headers your program requires here
+
+#endif /* TEST_TNET_STDAFX_H */
diff --git a/tinyNET/test/targetver.h b/tinyNET/test/targetver.h
new file mode 100644
index 0000000..21af608
--- /dev/null
+++ b/tinyNET/test/targetver.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_TARGETVER_H
+#define TNET_TEST_TARGETVER_H
+
+// The following macros define the minimum required platform. The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
+// your application. The macros work by enabling all features available on platform versions up to and
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#endif /* TNET_TEST_TARGETVER_H */ \ No newline at end of file
diff --git a/tinyNET/test/test.c b/tinyNET/test/test.c
new file mode 100644
index 0000000..64e0349
--- /dev/null
+++ b/tinyNET/test/test.c
@@ -0,0 +1,121 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#include "stdafx.h"
+
+#define BAIL_IF_ERR(expr) { int _ret_; if ((_ret_) = (expr)) { TSK_DEBUG_ERROR("Error %d", (_ret_)); goto bail; } }
+
+#include "tsk.h"
+
+#include "tinynet.h"
+
+#include "test_sockets.h"
+#include "test_transport.h"
+#include "test_auth.h"
+#include "test_stun.h"
+#include "test_nat.h"
+#include "test_ifaces.h"
+#include "test_dns.h"
+#include "test_ice.h"
+#include "test_dhcp.h"
+#include "test_dhcp6.h"
+#include "test_tls.h"
+
+#define RUN_TEST_LOOP 0
+
+#define RUN_TEST_ALL 0
+#define RUN_TEST_SOCKETS 0 /* FIXME: Android */
+#define RUN_TEST_TRANSPORT 0
+#define RUN_TEST_AUTH 0
+#define RUN_TEST_STUN 0
+#define RUN_TEST_ICE 1
+#define RUN_TEST_NAT 0
+#define RUN_TEST_IFACES 0
+#define RUN_TEST_DNS 0
+#define RUN_TEST_DHCP 0
+#define RUN_TEST_DHCP6 0
+#define RUN_TEST_TLS 0
+
+#ifdef _WIN32_WCE
+int _tmain(int argc, _TCHAR* argv[])
+#else
+int main()
+#endif
+{
+ /* Startup the network stack. */
+ if(tnet_startup()){
+ return -1;
+ }
+
+#if RUN_TEST_LOOP
+ for(;;)
+#endif
+ {
+
+#if RUN_TEST_ALL || RUN_TEST_SOCKETS
+ test_sockets();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_TRANSPORT
+ test_transport();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_AUTH
+ test_auth();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_STUN
+ test_stun();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_ICE
+ test_ice();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_NAT
+ test_nat();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_IFACES
+ test_ifaces();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_DNS
+ test_dns();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_DHCP
+ test_dhcp();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_DHCP6
+ test_dhcp6();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_TLS
+ test_tls();
+#endif
+
+ }
+
+ /* Cleanup the network stack */
+ tnet_cleanup();
+
+ return 0;
+}
+
diff --git a/tinyNET/test/test.vcproj b/tinyNET/test/test.vcproj
new file mode 100644
index 0000000..6b4162c
--- /dev/null
+++ b/tinyNET/test/test.vcproj
@@ -0,0 +1,418 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="test"
+ ProjectGUID="{2189FB5C-B2B2-4ED2-8A78-64853B55DAD5}"
+ RootNamespace="test"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\thirdparties\win32\include;&quot;$(SolutionDir)\src&quot;;..\..\tinySAK\src"
+ PreprocessorDefinitions="DEBUG_LEVEL=DEBUG_LEVEL_INFO;WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(OutDir)\tinySAK.lib $(OutDir)\tinyNET.lib ws2_32.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"
+ OutputDirectory="&quot;$(SolutionDir)$(ConfigurationName)\wce&quot;"
+ IntermediateDirectory="&quot;$(SolutionDir)$(ConfigurationName)&quot;"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="1"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ ExecutionBucket="7"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;$(DOUBANGO_HOME)\thirdparties\win32\include&quot;;&quot;$(SolutionDir)\src&quot;;&quot;$(DOUBANGO_HOME)\tinySAK\src&quot;"
+ PreprocessorDefinitions="DEBUG_LEVEL=DEBUG_LEVEL_INFO;_CONSOLE;_DEBUG;_WIN32_WCE=$(CEVER);UNDER_CE;$(PLATFORMDEFINES);WINCE;DEBUG;$(ARCHFAM);$(_ARCHFAM_)"
+ MinimalRebuild="true"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(OutDir)\tinySAK.lib $(OutDir)\tinyNET.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="8"
+ EntryPointSymbol="mainWCRTStartup"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCCodeSignTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"
+ OutputDirectory="$(SolutionDir)Windows Mobile 5.0 Pocket PC SDK (ARMV4I)\$(ConfigurationName)"
+ IntermediateDirectory="Windows Mobile 5.0 Pocket PC SDK (ARMV4I)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="1"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ ExecutionBucket="7"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCCodeSignTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ <DeploymentTool
+ ForceDirty="-1"
+ RemoteDirectory=""
+ RegisterOutput="0"
+ AdditionalFiles=""
+ />
+ <DebuggerTool
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\stdafx.c"
+ >
+ </File>
+ <File
+ RelativePath=".\test.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\stdafx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\targetver.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="tests"
+ >
+ <File
+ RelativePath=".\test_auth.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_dhcp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_dhcp6.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_dns.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_ice.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_ifaces.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_nat.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_sockets.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_stun.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_tls.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_transport.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/tinyNET/test/test_auth.h b/tinyNET/test/test_auth.h
new file mode 100644
index 0000000..5d51cd6
--- /dev/null
+++ b/tinyNET/test/test_auth.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_AUTH_H
+#define TNET_TEST_AUTH_H
+
+void test_auth()
+{
+
+}
+
+#endif /* TNET_TEST_AUTH_H */
+
diff --git a/tinyNET/test/test_dhcp.h b/tinyNET/test/test_dhcp.h
new file mode 100644
index 0000000..c74e99c
--- /dev/null
+++ b/tinyNET/test/test_dhcp.h
@@ -0,0 +1,118 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_DHCP_H
+#define TNET_TEST_DHCP_H
+
+
+
+void test_dhcp_discover(tnet_dhcp_ctx_t *ctx)
+{
+}
+
+void test_dhcp_offer(tnet_dhcp_ctx_t *ctx)
+{
+}
+
+void test_dhcp_request(tnet_dhcp_ctx_t *ctx)
+{
+}
+
+void test_dhcp_inform(tnet_dhcp_ctx_t *ctx)
+{
+ tnet_dhcp_params_t *params = tsk_null;
+ tnet_dhcp_reply_t *reply = tsk_null;
+
+ params = tnet_dhcp_params_create();
+ tnet_dhcp_params_add_code(params, dhcp_code_SIP_Servers_DHCP_Option); /* SIP Servers */
+ tnet_dhcp_params_add_code(params, dhcp_code_Domain_Server); /* DNS Server */
+
+ reply = tnet_dhcp_query_inform(ctx, params);
+
+ if(reply && !TNET_DHCP_MESSAGE_IS_REPLY(reply)){
+ TSK_DEBUG_ERROR("DHCP request is not expected in response to a request.");
+ goto bail;
+ }
+
+ if(reply){
+ switch(reply->type)
+ {
+ case dhcp_type_ack:
+ {
+ tsk_list_item_t *item;
+ TSK_DEBUG_INFO("DHCP response type ==> ACK.");
+
+ tsk_list_foreach(item, reply->options)
+ {
+ const tnet_dhcp_option_t *option = item->data;
+
+ /* SIP SERVERS */
+ if(option->code == dhcp_code_SIP_Servers_DHCP_Option)
+ {
+ tsk_list_item_t *item2;
+ const tnet_dhcp_option_sip_t *option_sip4 = (const tnet_dhcp_option_sip_t*)option;;
+ tsk_list_foreach(item2, option_sip4->servers)
+ {
+ const tsk_string_t *str = item2->data;
+ TSK_DEBUG_INFO("DHCP-SIP_SERVER ==>%s", str->value);
+ }
+ }
+
+ /* DNS SERVERS */
+ if(option->code == dhcp_code_Domain_Server)
+ {
+ tsk_list_item_t *item2;
+ const tnet_dhcp_option_dns_t *option_dns = (const tnet_dhcp_option_dns_t*)option;;
+ tsk_list_foreach(item2, option_dns->servers)
+ {
+ const tsk_string_t *str = item2->data;
+ TSK_DEBUG_INFO("DHCP-DNS_SERVER ==>%s", str->value);
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ TSK_DEBUG_ERROR("DHCP reply is NULL.");
+ goto bail;
+ }
+
+bail:
+ TSK_OBJECT_SAFE_FREE(reply);
+ TSK_OBJECT_SAFE_FREE(params);
+
+ //tsk_thread_sleep(1000);
+}
+
+void test_dhcp()
+{
+ tnet_dhcp_ctx_t *ctx = tnet_dhcp_ctx_create();
+ test_dhcp_inform(ctx);
+
+ TSK_OBJECT_SAFE_FREE(ctx);
+}
+
+#endif /* TNET_TEST_DHCP_H */
diff --git a/tinyNET/test/test_dhcp6.h b/tinyNET/test/test_dhcp6.h
new file mode 100644
index 0000000..c96fd96
--- /dev/null
+++ b/tinyNET/test/test_dhcp6.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_DHCP6_H
+#define TNET_TEST_DHCP6_H
+
+
+
+void test_dhcp6_requestinfo(tnet_dhcp6_ctx_t *ctx)
+{
+ tnet_dhcp6_option_orequest_t *orequest = tnet_dhcp6_option_orequest_create_null();
+ tnet_dhcp6_reply_t* reply = 0;
+
+ tnet_dhcp6_option_orequest_add_code(orequest, 24);
+ tnet_dhcp6_option_orequest_add_code(orequest, 23);
+ tnet_dhcp6_option_orequest_add_code(orequest, 21); /* SIP Servers Domain Name List */
+ tnet_dhcp6_option_orequest_add_code(orequest, 22); /* SIP Servers IPv6 Address List */
+
+ reply = tnet_dhcp6_requestinfo(ctx, orequest);
+
+ TSK_OBJECT_SAFE_FREE(orequest);
+ TSK_OBJECT_SAFE_FREE(reply);
+}
+
+void test_dhcp6()
+{
+ tnet_dhcp6_ctx_t *ctx = tnet_dhcp6_ctx_create();
+ test_dhcp6_requestinfo(ctx);
+
+ TSK_OBJECT_SAFE_FREE(ctx);
+}
+
+#endif /* TNET_TEST_DHCP6_H */
diff --git a/tinyNET/test/test_dns.h b/tinyNET/test/test_dns.h
new file mode 100644
index 0000000..f2ab145
--- /dev/null
+++ b/tinyNET/test/test_dns.h
@@ -0,0 +1,224 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_DNS_H
+#define TNET_TEST_DNS_H
+
+//#include "tnet_utils.h" /* tnet_address_t */
+
+void test_dns_query()
+{
+ tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+ tnet_dns_response_t *response = tsk_null;
+ const tsk_list_item_t* item;
+ const tnet_dns_rr_t* rr;
+
+ //if((response = tnet_dns_resolve(ctx, "_sip._udp.sip2sip.info", qclass_in, qtype_srv)))
+ if((response = tnet_dns_resolve(ctx, "sip2sip.info", qclass_in, qtype_naptr)))
+ {
+ if(TNET_DNS_RESPONSE_IS_SUCCESS(response)){
+ TSK_DEBUG_INFO("We got a success response from the DNS server.");
+ // loop through the answers
+ tsk_list_foreach(item, response->Answers){
+ rr = item->data;
+ if(rr->qtype == qtype_naptr){
+ const tnet_dns_naptr_t *naptr = (const tnet_dns_naptr_t*)rr;
+
+ TSK_DEBUG_INFO("order=%u pref=%u flags=%s services=%s regexp=%s replacement=%s",
+ naptr->order,
+ naptr->preference,
+ naptr->flags,
+ naptr->services,
+ naptr->regexp,
+ naptr->replacement);
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("We got an error response from the DNS server. Erro code: %u", response->Header.RCODE);
+ }
+ }
+
+ tnet_dns_cache_clear(ctx);
+
+ TSK_OBJECT_SAFE_FREE(response);
+ TSK_OBJECT_SAFE_FREE(ctx);
+
+
+ tsk_thread_sleep(2000);
+}
+
+void test_dns_srv()
+{
+ tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+ char* hostname = 0;
+ tnet_port_t port = 0;
+
+ if(!tnet_dns_query_srv(ctx, "_sip._udp.sip2sip.info", &hostname, &port)){
+ TSK_DEBUG_INFO("DNS SRV succeed ==> hostname=%s and port=%u", hostname, port);
+ }
+
+ TSK_FREE(hostname);
+ TSK_OBJECT_SAFE_FREE(ctx);
+
+ tsk_thread_sleep(2000);
+}
+
+void test_dns_naptr_srv()
+{
+ tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+ char* hostname = tsk_null;
+ tnet_port_t port = 0;
+
+ if(!tnet_dns_query_naptr_srv(ctx, "sip2sip.info", "SIP+D2U", &hostname, &port)){
+ TSK_DEBUG_INFO("DNS NAPTR+SRV succeed ==> hostname=%s and port=%u", hostname, port);
+ }
+
+ TSK_FREE(hostname);
+ TSK_OBJECT_SAFE_FREE(ctx);
+
+ tsk_thread_sleep(2000);
+}
+
+void test_enum()
+{
+ tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+ tnet_dns_response_t* response = tsk_null;
+// const tsk_list_item_t* item;
+// const tnet_dns_naptr_t* record;
+ char* uri = tsk_null;
+ const char* e164num = "+1-800-555-5555";
+ //const char* e164num = "+33660188661";
+
+ //tnet_dns_add_server(ctx, "192.168.16.9");
+
+ //if((uri = tnet_dns_enum_2(ctx, "E2U+SIP", e164num, "e164.org"))){
+ if((uri = tnet_dns_enum_2(ctx, "E2U+SIP", e164num, "e164.org"))){
+ TSK_DEBUG_INFO("URI=%s", uri);
+ TSK_FREE(uri);
+ }
+ else{
+ TSK_DEBUG_ERROR("ENUM(%s) failed", e164num);
+ }
+
+ /*if((response = tnet_dns_enum(ctx, "+1-800-555-5555", "e164.org"))){
+ if(TNET_DNS_RESPONSE_IS_SUCCESS(response)){
+ TSK_DEBUG_INFO("We got a success response from the DNS server.");
+ // loop through the answers
+ tsk_list_foreach(item, response->Answers){
+ record = item->data;
+
+ TSK_DEBUG_INFO("order=%u pref=%u flags=%s services=%s regexp=%s replacement=%s",
+ record->order,
+ record->preference,
+ record->flags,
+ record->services,
+ record->regexp,
+ record->replacement);
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("We got an error response from the DNS server. Erro code: %u", response->Header.RCODE);
+ }
+ }*/
+
+
+ TSK_OBJECT_SAFE_FREE(response);
+ TSK_OBJECT_SAFE_FREE(ctx);
+
+ tsk_thread_sleep(2000);
+}
+
+
+typedef struct regexp_test_s{
+ const char* e164num;
+ const char* regexp;
+ const char* xres;
+}
+regexp_test_t;
+
+regexp_test_t regexp_tests[] = {
+ "+18005551234", "!^.*$!sip:customer-service@example.com!i", "sip:customer-service@example.com",
+ "+18005551234", "!^.*$!mailto:information@example.com!i", "mailto:information@example.com",
+
+ "+18005555555", "!^\\+1800(.*)$!sip:1641641800\\1@tollfree.sip-happens.com!", "sip:16416418005555555@tollfree.sip-happens.com",
+ "+18005555555", "!^\\+1800(.*)$!sip:1641641800\\1@sip.tollfreegateway.com!", "sip:16416418005555555@sip.tollfreegateway.com",
+
+ "+468971234", "!^+46(.*)$!ldap://ldap.telco.se/cn=0\\1!", "ldap://ldap.telco.se/cn=08971234",
+ "+468971234", "!^+46(.*)$!mailto:spam@paf.se!", "mailto:spam@paf.se",
+
+ "urn:cid:199606121851.1@bar.example.com", "!!^urn:cid:.+@([^\\.]+\\.)(.*)$!\\2!i", "example.com",
+};
+
+void test_regex()
+{
+ char* ret;
+ size_t i;
+
+ for(i=0; i< sizeof(regexp_tests)/sizeof(regexp_test_t); i++)
+ {
+ if((ret = tnet_dns_regex_parse(regexp_tests[i].e164num, regexp_tests[i].regexp))){
+ TSK_DEBUG_INFO("ENUM(%s) = %s", regexp_tests[i].e164num, ret);
+ if(!tsk_strequals(ret, regexp_tests[i].xres)){
+ TSK_DEBUG_ERROR("Failed to match ENUM(%s)", regexp_tests[i].e164num);
+ }
+ TSK_FREE(ret);
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse ENUM(%s)", regexp_tests[i].e164num);
+ }
+
+ TSK_DEBUG_INFO("---------");
+ }
+}
+
+void test_resolvconf()
+{
+ tnet_addresses_L_t * servers;
+ const tnet_address_t* address;
+ const tsk_list_item_t* item;
+ const char* path = "C:\\tmp\\resolv32.conf";
+ //const char* path = "C:\\tmp\\resolv.conf";
+ //const char* path = "/etc/resolv.conf";
+
+ if((servers = tnet_dns_resolvconf_parse(path))){
+ tsk_list_foreach(item, servers){
+ address = item->data;
+
+ TSK_DEBUG_INFO("DNS Server host=%s Family=%d", address->ip, address->family);
+ }
+
+ TSK_OBJECT_SAFE_FREE(servers);
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse DNS servers from %s.", path);
+ }
+}
+
+void test_dns()
+{
+ test_dns_naptr_srv();
+ //test_dns_srv();
+ //test_dns_query();
+ //test_enum();
+ //test_regex();
+ //test_resolvconf();
+}
+
+
+#endif /* TNET_TEST_DNS_H */
diff --git a/tinyNET/test/test_ice.h b/tinyNET/test/test_ice.h
new file mode 100644
index 0000000..023a2c2
--- /dev/null
+++ b/tinyNET/test/test_ice.h
@@ -0,0 +1,238 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+
+#ifndef TNET_TEST_ICE_H
+#define TNET_TEST_ICE_H
+
+#undef kStunUsrName
+#undef kStunPwd
+
+#define kStunUsrName "bossiel@yahoo.fr"
+#define kStunPwd "tinynet"
+#define kStunServerIP "ns313841.ovh.net" /*"numb.viagenie.ca"*/ /*stun.ekiga.net*/
+
+#define kSkipHosts 1
+#define kSkipReflexives 1 // server reflexive: STUN
+#define kSkipPeers 1 // peer reflexive
+#define kSkipRelays 0 // relays: TURN
+
+#define kTurnTrue 1
+#define kStunTrue 1
+#define kTurnFalse 0
+#define kStunFalse 0
+
+static const tsk_bool_t use_rtcp = tsk_false;
+
+static struct tnet_ice_ctx_s *p_ice_ctx1 = tsk_null;
+static struct tnet_ice_ctx_s *p_ice_ctx2 = tsk_null;
+
+static void test_ice_print_local_candidates(const struct tnet_ice_ctx_s *pc_ctx)
+{
+ tsk_size_t index = 0;
+ const tnet_ice_candidate_t* candidate;
+ char* p_str = tsk_null;
+
+ while ((candidate = tnet_ice_ctx_get_local_candidate_at(pc_ctx, index++))) {
+ tsk_strcat_2(&p_str, "%s\r\n", tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate));
+ }
+ TSK_DEBUG_INFO("ICE LOCAL CANDIDATES:\n%s", p_str);
+ TSK_FREE(p_str);
+}
+
+static char* test_ice_get_local_candidates(const struct tnet_ice_ctx_s *pc_ctx)
+{
+ tsk_size_t index = 0;
+ const tnet_ice_candidate_t* candidate;
+ char* p_str = tsk_null;
+
+ while ((candidate = tnet_ice_ctx_get_local_candidate_at(pc_ctx, index++))) {
+ if (kSkipHosts && candidate->type_e == tnet_ice_cand_type_host) {
+ continue;
+ }
+ if (kSkipReflexives && candidate->type_e == tnet_ice_cand_type_srflx) {
+ continue;
+ }
+ if (kSkipRelays && candidate->type_e == tnet_ice_cand_type_relay) {
+ continue;
+ }
+ if (kSkipPeers && candidate->type_e == tnet_ice_cand_type_prflx) {
+ continue;
+ }
+ tsk_strcat_2(&p_str, "%s\r\n", tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate));
+ }
+ return p_str;
+}
+
+static int test_ice_rtp_callback(const void* callback_data, const uint8_t* data_ptr, tsk_size_t data_size, tnet_fd_t local_fd, const struct sockaddr_storage* remote_addr)
+{
+ struct tnet_ice_ctx_s *p_ice_ctx = (struct tnet_ice_ctx_s *)callback_data;
+
+ TSK_DEBUG_INFO("\n\nICE rtp callback (incoming data): %.*s\n\n", data_size, data_ptr);
+
+#if 0
+ tnet_ice_ctx_send_turn_rtp(p_ice_ctx, data_ptr, data_size);
+#endif
+
+ return 0;
+}
+
+static int test_ice_state_callback(const tnet_ice_event_t *e)
+{
+ struct tnet_ice_ctx_s *p_ice_ctx = (struct tnet_ice_ctx_s *)e->ctx;
+ int ret = 0;
+
+ TSK_DEBUG_INFO("ICE state callback: %s", e->phrase);
+
+ switch(e->type)
+ {
+ case tnet_ice_event_type_gathering_completed:
+ {
+ test_ice_print_local_candidates(p_ice_ctx);
+ if (p_ice_ctx == p_ice_ctx1) {
+ if ((ret = tnet_ice_ctx_start(p_ice_ctx2))) {
+ goto bail;
+ }
+ }
+ else {
+ const tnet_ice_candidate_t* candidate;
+ char* p_cand;
+
+ p_cand = test_ice_get_local_candidates(p_ice_ctx2);
+ candidate = tnet_ice_ctx_get_local_candidate_first(p_ice_ctx2);
+ ret = tnet_ice_ctx_set_remote_candidates(p_ice_ctx1, p_cand, candidate->ufrag, candidate->pwd, tsk_true, tsk_false);
+ if (ret == 0) {
+ TSK_FREE(p_cand);
+ p_cand = test_ice_get_local_candidates(p_ice_ctx1);
+ candidate = tnet_ice_ctx_get_local_candidate_first(p_ice_ctx1);
+ ret = tnet_ice_ctx_set_remote_candidates(p_ice_ctx2, p_cand, candidate->ufrag, candidate->pwd, tsk_false, tsk_false);
+ TSK_FREE(p_cand);
+ }
+ }
+ break;
+ }
+
+ case tnet_ice_event_type_conncheck_succeed:
+ {
+ const char kTurnData[] = "TURN data to send for testing";
+ const tnet_ice_candidate_t *candidate_offer, *candidate_answer_src, *candidate_answer_dest;
+
+ // === RTP === //
+ ret = tnet_ice_ctx_get_nominated_symetric_candidates(p_ice_ctx, TNET_ICE_CANDIDATE_COMPID_RTP, &candidate_offer, &candidate_answer_src, &candidate_answer_dest);
+ if (ret == 0) {
+ TSK_DEBUG_INFO("Nominated candidate(RTP): Offer=[[%s]], AnswerSrc=[[%s]], AnswerDest=[[%s]]",
+ tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_offer),
+ tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_answer_src),
+ tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_answer_dest));
+
+ if (tnet_ice_ctx_is_turn_rtp_active(p_ice_ctx)) {
+ tnet_ice_ctx_send_turn_rtp(p_ice_ctx, kTurnData, sizeof(kTurnData));
+ }
+ }
+ // === RTCP === //
+ if (use_rtcp) {
+ ret = tnet_ice_ctx_get_nominated_symetric_candidates(p_ice_ctx, TNET_ICE_CANDIDATE_COMPID_RTCP, &candidate_offer, &candidate_answer_src, &candidate_answer_dest);
+ if (ret == 0) {
+ TSK_DEBUG_INFO("Nominated candidate(RTCP): Offer=[[%s]], AnswerSrc=[[%s]], AnswerDest=[[%s]]",
+ tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_offer),
+ tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_answer_src),
+ tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_answer_dest));
+ if (tnet_ice_ctx_is_turn_rtcp_active(p_ice_ctx)) {
+ tnet_ice_ctx_send_turn_rtcp(p_ice_ctx, kTurnData, sizeof(kTurnData));
+ }
+ }
+ }
+ break;
+ }
+ }
+
+bail:
+ return ret;
+}
+
+void test_ice()
+{
+ int ret;
+ static const tsk_bool_t use_ipv6 = tsk_false;
+ static const tsk_bool_t use_ice_jingle = tsk_false;
+ static const tsk_bool_t use_video = tsk_false;
+
+ if (!(p_ice_ctx1 = tnet_ice_ctx_create(use_ice_jingle, use_ipv6, use_rtcp, use_video, test_ice_state_callback, tsk_null))) {
+ goto bail;
+ }
+ if (!(p_ice_ctx2 = tnet_ice_ctx_create(use_ice_jingle, use_ipv6, use_rtcp, use_video, test_ice_state_callback, tsk_null))) {
+ goto bail;
+ }
+ if ((ret = tnet_ice_ctx_set_turn_enabled(p_ice_ctx1, 1))) {
+ goto bail;
+ }
+ if ((ret = tnet_ice_ctx_set_turn_enabled(p_ice_ctx2, 1))) {
+ goto bail;
+ }
+ if ((ret = tnet_ice_ctx_set_stun_enabled(p_ice_ctx1, 1))) {
+ goto bail;
+ }
+ if ((ret = tnet_ice_ctx_set_stun_enabled(p_ice_ctx2, 1))) {
+ goto bail;
+ }
+ if ((ret = tnet_ice_ctx_set_userdata(p_ice_ctx1, p_ice_ctx1))) {
+ goto bail;
+ }
+ if ((ret = tnet_ice_ctx_set_userdata(p_ice_ctx2, p_ice_ctx2))) {
+ goto bail;
+ }
+ if ((ret = tnet_ice_ctx_rtp_callback(p_ice_ctx1, test_ice_rtp_callback, p_ice_ctx1))) {
+ goto bail;
+ }
+ if ((ret = tnet_ice_ctx_rtp_callback(p_ice_ctx2, test_ice_rtp_callback, p_ice_ctx2))) {
+ goto bail;
+ }
+#if 0 //@deprecated
+ if ((ret = tnet_ice_ctx_set_stun(p_ice_ctx1, kStunServerIP, 3478, kStunSoftware, kStunUsrName, kStunPwd))) {
+ goto bail;
+ }
+ if ((ret = tnet_ice_ctx_set_stun(p_ice_ctx2, kStunServerIP, 3478, kStunSoftware, kStunUsrName, kStunPwd))) {
+ goto bail;
+ }
+#else
+ tnet_ice_ctx_add_server(p_ice_ctx1, "udp", kStunServerIP, 3478, kTurnFalse, kStunTrue, kStunUsrName, kStunPwd); // STUN-UDP
+ tnet_ice_ctx_add_server(p_ice_ctx1, "tcp", kStunServerIP, 3478, kTurnTrue, kStunFalse, kStunUsrName, kStunPwd); // TURN-TCP
+ tnet_ice_ctx_add_server(p_ice_ctx2, "udp", kStunServerIP, 3478, kTurnFalse, kStunTrue, kStunUsrName, kStunPwd); // STUN-UDP
+ tnet_ice_ctx_add_server(p_ice_ctx2, "tcp", kStunServerIP, 3478, kTurnTrue, kStunFalse, kStunUsrName, kStunPwd); // TURN-TCP
+#endif
+ if ((ret = tnet_ice_ctx_start(p_ice_ctx1))) {
+ goto bail;
+ }
+ // start ctx2 when we finish gathering ctx1's candidates
+ //if ((ret = tnet_ice_ctx_start(p_ice_ctx2))) {
+ // goto bail;
+ //}
+
+ getchar();
+
+ // ret = tnet_ice_ctx_stop(p_ice_ctx1);
+ // ret = tnet_ice_ctx_stop(p_ice_ctx2);
+
+bail:
+ TSK_OBJECT_SAFE_FREE(p_ice_ctx1);
+ TSK_OBJECT_SAFE_FREE(p_ice_ctx2);
+}
+
+
+#endif /* TNET_TEST_ICE_H */
+
diff --git a/tinyNET/test/test_ifaces.h b/tinyNET/test/test_ifaces.h
new file mode 100644
index 0000000..2fd4e43
--- /dev/null
+++ b/tinyNET/test/test_ifaces.h
@@ -0,0 +1,99 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_IFACES_H
+#define TNET_TEST_IFACES_H
+
+void test_faces_bestsource()
+{
+ tnet_ip_t source;
+
+ // IPv6
+ if(!tnet_getbestsource("fe80::fe4c:3ea1", 5060, tnet_socket_type_udp_ipv6, &source)){
+ TSK_DEBUG_INFO("Best IPv6 source is [%s]", source);
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to get best IPv6 source.");
+ }
+ // IPv6
+ if(!tnet_getbestsource("2a01:e35:8b32:7050:212:f0ff:fe4c:3ea1", 5060, tnet_socket_type_udp_ipv6, &source)){
+ TSK_DEBUG_INFO("Best IPv6 source is [%s]", source);
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to get best IPv6 source.");
+ }
+ // IPv4
+ if(!tnet_getbestsource("192.168.0.11", 5060, tnet_socket_type_udp_ipv4, &source)){
+ TSK_DEBUG_INFO("Best IPv4 source is [%s]", source);
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to get best IPv4 source.");
+ }
+}
+
+void test_ifaces_dump_ifaces()
+{
+ tnet_interfaces_L_t* ifaces = tnet_get_interfaces();
+ tsk_list_item_t *item;
+
+ tsk_list_foreach(item, ifaces)
+ {
+ const tnet_interface_t *iface = item->data;
+ TSK_DEBUG_INFO("Interface: %s", iface->description);
+ }
+
+ TSK_OBJECT_SAFE_FREE(ifaces);
+}
+
+void test_ifaces_dump_addresses()
+{
+ tnet_addresses_L_t* addresses = tnet_get_addresses_all();
+ tsk_list_item_t *item;
+
+ tsk_list_foreach(item, addresses)
+ {
+ const tnet_address_t *address = item->data;
+ if(address->anycast)
+ {
+ TSK_DEBUG_INFO("ANYCAST address: %s", address->ip);
+ }
+ else if(address->unicast)
+ {
+ TSK_DEBUG_INFO("UNICAST address: %s", address->ip);
+ }
+ else if(address->multicast)
+ {
+ TSK_DEBUG_INFO("MULTICAST address: %s", address->ip);
+ }
+ else if(address->dnsserver)
+ {
+ TSK_DEBUG_INFO("DNSSERVER address: %s", address->ip);
+ }
+ }
+
+ TSK_OBJECT_SAFE_FREE(addresses);
+}
+
+void test_ifaces()
+{
+ test_faces_bestsource();
+ test_ifaces_dump_ifaces();
+ test_ifaces_dump_addresses();
+}
+
+#endif /* TNET_TEST_IFACES_H */
diff --git a/tinyNET/test/test_nat.h b/tinyNET/test/test_nat.h
new file mode 100644
index 0000000..1a9bd68
--- /dev/null
+++ b/tinyNET/test/test_nat.h
@@ -0,0 +1,211 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_NAT_H
+#define TNET_TEST_NAT_H
+
+#define STUN_SERVER_IP "ns313841.ovh.net" // "numb.viagenie.ca" /* stun.ekiga.net, */
+#define STUN_USERNAME "bossiel@yahoo.fr"
+#define STUN_PASSWORD "tinynet"
+#define STUN_SERVER_PORT TNET_STUN_TCP_UDP_DEFAULT_PORT
+#define STUN_SERVER_PROTO tnet_socket_type_udp_ipv4
+
+void test_nat_stun()
+{
+ tnet_socket_t *socket1 = 0, *socket2 = 0;
+ struct tnet_nat_ctx_s *context = 0;
+
+ tnet_stun_binding_id_t bind_id1, bind_id2;
+
+ char* public_ip1 = 0, *public_ip2 = 0;
+ tnet_port_t public_port1 = 0, public_port2 = 0;
+
+ if(!(socket1 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, STUN_SERVER_PROTO))
+ || !(socket2 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, STUN_SERVER_PROTO))) {
+ goto bail;
+ }
+
+ context = tnet_nat_context_create(STUN_SERVER_PROTO, STUN_USERNAME, STUN_PASSWORD);
+
+ if(tnet_nat_set_server_address(context, STUN_SERVER_IP)) {
+ TSK_DEBUG_ERROR("Failed to set STUN/TURN address.");
+ goto bail;
+ }
+
+ // == BIND == //
+ bind_id1 = tnet_nat_stun_bind(context, socket1->fd);
+ bind_id2 = tnet_nat_stun_bind(context, socket2->fd);
+
+ if(!bind_id1 || !bind_id2) {
+ TSK_DEBUG_ERROR("Failed to get public IP/port using stun");
+ goto bail;
+ }
+
+ if (tnet_nat_stun_get_reflexive_address(context, bind_id1, &public_ip1, &public_port1) == 0) {
+ TSK_DEBUG_INFO("Public IP1/Port1 ==> %s:%u", public_ip1, public_port1);
+ }
+
+ if (tnet_nat_stun_get_reflexive_address(context, bind_id2, &public_ip2, &public_port2) == 0) {
+ TSK_DEBUG_INFO("Public IP2/Port2 ==> %s:%u", public_ip2, public_port2);
+ }
+
+ // == UNBIND == //
+ tnet_nat_stun_unbind(context, bind_id1);
+ tnet_nat_stun_unbind(context, bind_id2);
+
+bail:
+ TSK_OBJECT_SAFE_FREE(socket1);
+ TSK_OBJECT_SAFE_FREE(socket2);
+
+ TSK_FREE(public_ip1);
+ TSK_FREE(public_ip1);
+
+ TSK_OBJECT_SAFE_FREE(context);
+}
+
+void test_nat_turn()
+{
+// tnet_socket_t *socket1 = 0, *socket2 = 0;
+// struct tnet_nat_ctx_s *context = 0;
+// tnet_turn_allocation_id_t alloc_id1, alloc_id2;
+//
+// char* public_ip1 = 0, *public_ip2 = 0;
+// tnet_port_t public_port1 = 0, public_port2 = 0;
+//
+// tnet_turn_channel_binding_id_t channel_id;
+//
+// int ret;
+//
+// if(!(socket1 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, STUN_SERVER_PROTO))
+// || !(socket2 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, STUN_SERVER_PROTO)))
+// {
+// goto bail;
+// }
+//
+// context = tnet_nat_context_create(STUN_SERVER_PROTO, STUN_USERNAME, STUN_PASSWORD);
+// ((tnet_nat_context_t*)context)->enable_evenport = 0;
+// ((tnet_nat_context_t*)context)->enable_fingerprint = 0;
+// ((tnet_nat_context_t*)context)->enable_dontfrag = 0;
+// ((tnet_nat_context_t*)context)->enable_integrity = 0;
+//
+// if(tnet_nat_set_server_address(context, STUN_SERVER_IP))
+// {
+// TSK_DEBUG_ERROR("Failed to set STUN/TURN address.");
+// goto bail;
+// }
+//
+// /* == ALLOC
+// */
+// alloc_id1 = tnet_nat_turn_allocate(context, socket1->fd);
+// alloc_id2 = tnet_nat_turn_allocate(context, socket2->fd);
+// if(!TNET_TURN_IS_VALID_ALLOCATION_ID(alloc_id1) || !TNET_TURN_IS_VALID_ALLOCATION_ID(alloc_id2))
+// {
+// TSK_DEBUG_ERROR("TURN allocation failed.");
+// goto bail;
+// }
+// else
+// {
+// TSK_DEBUG_INFO("TURN allocation succeeded and id1=%llu and id2=%llu", alloc_id1, alloc_id2);
+// }
+//
+// tsk_thread_sleep(2000);
+//
+// /* == RETRIEVE STUN SERVER REFLEXIVE ADDRESSES
+// */
+// if(!tnet_nat_turn_get_reflexive_address(context, alloc_id1, &public_ip1, &public_port1))
+// {
+// TSK_DEBUG_INFO("Public IP1/Port1 ==> %s:%u", public_ip1, public_port1);
+// }
+//
+// if(!tnet_nat_turn_get_reflexive_address(context, alloc_id2, &public_ip2, &public_port2))
+// {
+// TSK_DEBUG_INFO("Public IP2/Port2 ==> %s:%u", public_ip2, public_port2);
+// }
+//
+// /* == CREATE PERMISSION
+// */
+// //tnet_nat_turn_add_permission(context, alloc_id1, "192.168.0.11", 300);
+//
+// /* == CHANNEL BINDING
+// */
+// {
+// /* Try to bind (channel binding) to the socket1 to socket2 */
+// struct sockaddr_storage peer;
+// if((ret = tnet_sockaddr_init(public_ip2, public_port2, STUN_SERVER_PROTO, &peer)))
+// {
+// TSK_DEBUG_ERROR("Failed to init peer with error code %d.", ret);
+// }
+// else
+// {
+// channel_id = tnet_nat_turn_channel_bind(context, alloc_id1,&peer);
+// if(TNET_TURN_IS_VALID_CHANNEL_BINDING_ID(channel_id))
+// {
+// TSK_DEBUG_INFO("TURN channel binding succeeded.");
+//
+// /* Try to send data using the newly create channel */
+// if(tnet_nat_turn_channel_senddata(context, channel_id, "Doubango", strlen("Doubango")))
+// {
+// TSK_DEBUG_ERROR("Failed to send data using channel id [%u].", channel_id);
+// }
+// else
+// {
+// TSK_DEBUG_INFO("Data successfuly sent using channel if[%u].", channel_id);
+// }
+// }
+// else
+// {
+// TSK_DEBUG_ERROR("TURN channel binding failed.");
+// }
+// }
+// }
+//
+// tsk_thread_sleep(2000);
+//
+// /* == UNALLOC
+// */
+// if((ret = tnet_nat_turn_unallocate(context, alloc_id1)) || (ret = tnet_nat_turn_unallocate(context, alloc_id2)))
+// {
+// TSK_DEBUG_ERROR("TURN unallocation failed with error code: %d.", ret);
+// goto bail;
+// }
+// else
+// {
+// TSK_DEBUG_INFO("TURN unallocation succeeded.");
+// }
+//
+//bail:
+// TSK_OBJECT_SAFE_FREE(socket1);
+// TSK_OBJECT_SAFE_FREE(socket2);
+//
+// TSK_FREE(public_ip1);
+// TSK_FREE(public_ip1);
+//
+// TSK_OBJECT_SAFE_FREE(context);
+}
+
+
+void test_nat()
+{
+ test_nat_stun();
+ //test_nat_turn();
+ //tsk_thread_sleep(1000);
+}
+
+
+
+#endif /* TNET_TEST_NAT_H */
diff --git a/tinyNET/test/test_sockets.h b/tinyNET/test/test_sockets.h
new file mode 100644
index 0000000..3edd1bd
--- /dev/null
+++ b/tinyNET/test/test_sockets.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_SOCKETS_H
+#define TNET_TEST_SOCKETS_H
+
+void test_sockets()
+{
+ int test;
+ tnet_socket_tcp_t * tcp_socket;
+ tnet_socket_type_t type = tnet_socket_type_udp_ipv4;
+ struct sockaddr_storage to;
+
+ TNET_SOCKET_TYPE_SET_IPV4(type);
+ TNET_SOCKET_TYPE_SET_IPV6(type);
+ TNET_SOCKET_TYPE_SET_IPV4Only(type);
+ TNET_SOCKET_TYPE_SET_IPV6Only(type);
+ TNET_SOCKET_TYPE_SET_IPV6Only(type);
+ TNET_SOCKET_TYPE_SET_IPV4(type);
+ TNET_SOCKET_TYPE_SET_IPV6(type);
+
+ TNET_SOCKET_TYPE_SET_TLS(type);
+ TNET_SOCKET_TYPE_SET_UDP(type);
+ TNET_SOCKET_TYPE_SET_SCTP(type);
+ TNET_SOCKET_TYPE_SET_TCP(type);
+
+ tcp_socket = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, type);
+
+ if(!TNET_SOCKET_IS_VALID(tcp_socket))
+ {
+ TSK_OBJECT_SAFE_FREE(tcp_socket);
+ return;
+ }
+
+ //if(!(test = tnet_sockaddr_init("www.google.com", 80, type, &to))){
+ // test = tnet_sockfd_connetto(tcp_socket->fd, (const struct sockaddr_storage *)&to);
+ //}
+
+ if(!(test = tnet_sockaddr_init("ipv6.google.com", 80, type, &to))){
+ test = tnet_sockfd_connectto(tcp_socket->fd, (const struct sockaddr_storage *)&to);
+ }
+
+ TSK_OBJECT_SAFE_FREE(tcp_socket);
+}
+
+#endif /* TNET_TEST_SOCKETS_H */
diff --git a/tinyNET/test/test_stun.h b/tinyNET/test/test_stun.h
new file mode 100644
index 0000000..58fc9b1
--- /dev/null
+++ b/tinyNET/test/test_stun.h
@@ -0,0 +1,255 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_STUN_H
+#define TNET_TEST_STUN_H
+
+#include "stun/tnet_stun_pkt.h"
+#include "stun/tnet_stun_utils.h"
+#include "turn/tnet_turn_session.h"
+
+#define kStunUsrName "bossiel@yahoo.fr"
+#define kStunPwd "tinynet"
+#define kStunServerIP "ns313841.ovh.net" /*"numb.viagenie.ca"*/
+#define kStunServerPort kStunPortDefaultTcpUdp
+#define kStunServerProto tnet_socket_type_udp_ipv4
+#define kTurnPeerIP "192.168.0.37"
+#define kTurnPeerPort 2020
+
+#define TNET_TEST_STUN_SEND_BUFF_TO(buff_ptr, buff_size, IP, PORT) \
+ { \
+ struct sockaddr_storage addr_to; \
+ tnet_socket_t* socket = tnet_socket_create(0, 0, kStunServerProto); \
+ tnet_sockaddr_init((IP), (PORT), kStunServerProto, &addr_to); \
+ tnet_sockfd_sendto(socket->fd, (const struct sockaddr *)&addr_to, (buff_ptr), (buff_size)); \
+ TSK_OBJECT_SAFE_FREE(socket); \
+ }
+#define TNET_TEST_STUN_SEND_BUFF(buff_ptr, buff_size) TNET_TEST_STUN_SEND_BUFF_TO((buff_ptr), (buff_size), kStunServerIP, kStunServerPort)
+
+uint8_t __parse_buff_write_ptr[1200];
+static const tsk_size_t __parse_buff_write_size = sizeof(__parse_buff_write_ptr)/sizeof(__parse_buff_write_ptr[0]);
+uint8_t __parse_buff_read_ptr[1200];
+static const tsk_size_t __parse_buff_read_size = sizeof(__parse_buff_read_ptr)/sizeof(__parse_buff_read_ptr[0]);
+
+// http://tools.ietf.org/html/draft-ietf-behave-stun-test-vectors-04
+
+static int test_stun_buff_cmp(const uint8_t* pc_buf1_ptr, tsk_size_t n_buff1_size, const uint8_t* pc_buf2_ptr, tsk_size_t n_buff2_size)
+{
+ int ret;
+ tsk_size_t u;
+ if (!pc_buf1_ptr || !pc_buf2_ptr || (n_buff1_size != n_buff2_size)) {
+ return -1;
+ }
+ for (u = 0; u < n_buff1_size; ++u) {
+ if ((ret = (pc_buf1_ptr[u] - pc_buf2_ptr[u]))) {
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static void test_stun_parser()
+{
+ tnet_stun_pkt_t* p_pkt = tsk_null;
+ tsk_size_t n_written_bytes, n_read_bytes;
+ static const char* __pc_mapped_addr_ipv4 = "192.168.0.37";
+ static const char* __pc_mapped_addr_ipv6 = "fdf8:f53b:82e4::53";
+ static const uint16_t __u_mapped_addr_port = 5060;
+ static const char __pc_username[] = "Mamadou DIOP";
+ static const uint16_t __u_username = sizeof(__pc_username);
+ static const char __pc_integrity[TSK_SHA1_DIGEST_SIZE] = { 0 };
+ static const uint16_t __u_integrity = sizeof(__pc_integrity);
+ static const uint32_t __u_fingerprint = 19831983;
+ static const uint8_t __u_error_class = 4; // (4 * 100) = 404
+ static const uint8_t __u_error_number = 4; // + 4 = 404
+ static const char* __pc_error_reason = "Not Found";
+ tnet_stun_addr_t addr_ipv4, addr_ipv6;
+ static const char __pc_realm[] = "doubango.org";
+ static const uint16_t __u_realm = sizeof(__pc_realm);
+ static const char __pc_nonce[128] = { 0 };
+ static const uint16_t __u_nonce = sizeof(__pc_nonce);
+ static const char __pc_software[] = "tinyNET 2.0";
+ static const uint16_t __u_software = sizeof(__pc_software);
+ static const uint32_t __u_life_time = 600;
+ static const uint32_t __u_req_transport = 17; // UDP
+
+ (n_read_bytes);
+
+ BAIL_IF_ERR(tnet_stun_pkt_create_empty(tnet_stun_pkt_type_binding_request, &p_pkt));
+ BAIL_IF_ERR(tnet_stun_utils_inet_pton_v4(__pc_mapped_addr_ipv4, &addr_ipv4));
+ BAIL_IF_ERR(tnet_stun_utils_inet_pton_v6(__pc_mapped_addr_ipv6, &addr_ipv6));
+ BAIL_IF_ERR(tnet_stun_pkt_attrs_add(p_pkt,
+ TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS_V4(__u_mapped_addr_port, &addr_ipv4),
+ TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS_V6(__u_mapped_addr_port, &addr_ipv6),
+ TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS_V4(__u_mapped_addr_port, &addr_ipv4),
+ TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS_V6(__u_mapped_addr_port, &addr_ipv6),
+ TNET_STUN_PKT_ATTR_ADD_USERNAME_ZT(__pc_username),
+ TNET_STUN_PKT_ATTR_ADD_MESSAGE_INTEGRITY(__pc_integrity, __u_integrity),
+ TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(__u_error_class, __u_error_number, __pc_error_reason),
+ TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_TRY_ALTERNATE(),
+ TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_BAD_REQUEST(),
+ TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_UNAUTHORIZED(),
+ TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_UNKNOWN_ATTRIBUTE(),
+ TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_STALE_NONCE(),
+ TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_SERVER_ERROR(),
+ TNET_STUN_PKT_ATTR_ADD_REALM_ZT(__pc_realm),
+ TNET_STUN_PKT_ATTR_ADD_NONCE(__pc_nonce, __u_nonce),
+
+ TNET_STUN_PKT_ATTR_ADD_UNKNOWN_ATTRS(
+ TNET_STUN_PKT_ATTR_ADD_UNKNOWN_ATTRS_VAL(0x0001), // MAPPED-ADDRESS
+ TNET_STUN_PKT_ATTR_ADD_UNKNOWN_ATTRS_VAL(0x0006), // USERNAME
+ TNET_STUN_PKT_ATTR_ADD_UNKNOWN_ATTRS_VAL(0x0007), // PASSWORD
+ TNET_STUN_PKT_ATTR_ADD_NULL()),
+
+ TNET_STUN_PKT_ATTR_ADD_SOFTWARE_ZT(__pc_software),
+ TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER_V4(__u_mapped_addr_port, &addr_ipv4),
+ TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER_V6(__u_mapped_addr_port, &addr_ipv6),
+ TNET_STUN_PKT_ATTR_ADD_LIFETIME(__u_life_time),
+ TNET_STUN_PKT_ATTR_ADD_REQUESTED_TRANSPORT(__u_req_transport),
+ TNET_STUN_PKT_ATTR_ADD_DONT_FRAGMENT(),
+
+ TNET_STUN_PKT_ATTR_ADD_FINGERPRINT(__u_fingerprint),
+ TNET_STUN_PKT_ATTR_ADD_NULL()));
+ BAIL_IF_ERR(tnet_stun_pkt_write_with_padding(p_pkt, __parse_buff_write_ptr, __parse_buff_write_size, &n_written_bytes));
+ TNET_TEST_STUN_SEND_BUFF(__parse_buff_write_ptr, n_written_bytes);
+
+ TSK_OBJECT_SAFE_FREE(p_pkt);
+ BAIL_IF_ERR(tnet_stun_pkt_read(__parse_buff_write_ptr, n_written_bytes, &p_pkt));
+ BAIL_IF_ERR(tnet_stun_pkt_write_with_padding(p_pkt, __parse_buff_read_ptr, __parse_buff_read_size, &n_read_bytes));
+ //TNET_TEST_STUN_SEND_BUFF(__parse_buff_read_ptr, n_read_bytes);
+
+ BAIL_IF_ERR(test_stun_buff_cmp(__parse_buff_write_ptr, n_written_bytes, __parse_buff_read_ptr, n_read_bytes));
+ TSK_DEBUG_INFO("test_stun_parser...OK");
+
+bail:
+ TSK_OBJECT_SAFE_FREE(p_pkt);
+}
+
+static struct tnet_turn_session_s* __pc_ss1 = tsk_null;
+static struct tnet_turn_session_s* __pc_ss2 = tsk_null;
+static char* __p_rel_ip_ss1 = tsk_null;
+static uint16_t __u_rel_port_ss1 = 0;
+static tsk_bool_t __b_rel_ipv6_ss1 = 0;
+static tnet_turn_peer_id_t __u_peer_id1 = kTurnPeerIdInvalid;
+static char* __p_rel_ip_ss2 = tsk_null;
+static uint16_t __u_rel_port_ss2 = 0;
+static tsk_bool_t __b_rel_ipv6_ss2 = 0;
+static tnet_turn_peer_id_t __u_peer_id2 = kTurnPeerIdInvalid;
+
+static int _test_turn_session_callback(const struct tnet_turn_session_event_xs *e)
+{
+ const struct tnet_turn_session_s* pc_ss = (const struct tnet_turn_session_s*)e->pc_usr_data;
+ int ret = 0;
+ switch (e->e_type) {
+ case tnet_turn_session_event_type_alloc_ok:
+ {
+ uint16_t *pu_port = (pc_ss == __pc_ss2) ? &__u_rel_port_ss1 : &__u_rel_port_ss2;
+ char** pp_ip = (pc_ss == __pc_ss2) ? &__p_rel_ip_ss1 : &__p_rel_ip_ss2;
+ tsk_bool_t *pb_ipv6 = (pc_ss == __pc_ss2) ? &__b_rel_ipv6_ss1 : &__b_rel_ipv6_ss2;
+ tnet_turn_peer_id_t *pu_peer_id = (pc_ss == __pc_ss2) ? &__u_peer_id2 : &__u_peer_id1;
+
+ BAIL_IF_ERR(tnet_turn_session_get_relayed_addr(pc_ss, pp_ip, pu_port, pb_ipv6));
+ // BAIL_IF_ERR(tnet_turn_session_get_srflx_addr(pc_ss, pu_port, &u_port, &b_ipv6)); // get my own server reflexive address (in order to send data to myself)
+ BAIL_IF_ERR(tnet_turn_session_createpermission((struct tnet_turn_session_s*)pc_ss, *pp_ip, *pu_port, pu_peer_id)); // Input = ADDR(remote.candidate.relay)
+ break;
+ }
+ case tnet_turn_session_event_type_alloc_nok:
+ {
+ TSK_DEBUG_INFO("*** TURN ALLOC NOK ***");
+ break;
+ }
+ case tnet_turn_session_event_type_perm_ok:
+ {
+ static const char __pc_data[] = { "TURN Sample Data (Send Indication)" };
+ int i;
+ tnet_turn_peer_id_t u_peer_id = (pc_ss == __pc_ss2) ? __u_peer_id2 : __u_peer_id1;
+ // Bind a channel (not required). If succeed, will be used to save data.
+ tnet_turn_session_chanbind((struct tnet_turn_session_s*)pc_ss, u_peer_id);
+ // Send data (will use channel if one is active. Otherwise (no channel), SendIndications will be used)
+ for (i = 0; i < 10; ++i) {
+ BAIL_IF_ERR(tnet_turn_session_send_data((struct tnet_turn_session_s*)pc_ss, u_peer_id, __pc_data, sizeof(__pc_data)));
+ }
+ break;
+ }
+ case tnet_turn_session_event_type_perm_nok:
+ {
+ TSK_DEBUG_INFO("*** TURN PERM NOK ***");
+ break;
+ }
+ case tnet_turn_session_event_type_chanbind_ok:
+ {
+ static const char __pc_data[] = { "TURN Sample Data (ChannelData)" };
+ int i;
+ tnet_turn_peer_id_t u_peer_id = (pc_ss == __pc_ss2) ? __u_peer_id2 : __u_peer_id1;
+ for (i = 0; i < 10; ++i) {
+ BAIL_IF_ERR(tnet_turn_session_send_data((struct tnet_turn_session_s*)pc_ss, u_peer_id, __pc_data, sizeof(__pc_data)));
+ }
+ break;
+ }
+ case tnet_turn_session_event_type_chanbind_nok:
+ {
+ TSK_DEBUG_INFO("*** TURN CHANBIND NOK ***");
+ break;
+ }
+ case tnet_turn_session_event_type_recv_data:
+ {
+ TSK_DEBUG_INFO("RECV DATA:%.*s", e->data.u_data_size, (const char*)e->data.pc_data_ptr);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+bail:
+ return ret;
+}
+
+static void test_turn_session()
+{
+ BAIL_IF_ERR(tnet_turn_session_create_udp_ipv4(tnet_turn_transport_udp, kStunServerIP, kStunServerPort, &__pc_ss1));
+ BAIL_IF_ERR(tnet_turn_session_set_callback(__pc_ss1, _test_turn_session_callback, __pc_ss1));
+ BAIL_IF_ERR(tnet_turn_session_set_cred(__pc_ss1, kStunUsrName, kStunPwd));
+ BAIL_IF_ERR(tnet_turn_session_prepare(__pc_ss1));
+ BAIL_IF_ERR(tnet_turn_session_start(__pc_ss1));
+
+ BAIL_IF_ERR(tnet_turn_session_create_udp_ipv4(tnet_turn_transport_udp, kStunServerIP, kStunServerPort, &__pc_ss2));
+ BAIL_IF_ERR(tnet_turn_session_set_callback(__pc_ss2, _test_turn_session_callback, __pc_ss2));
+ BAIL_IF_ERR(tnet_turn_session_set_cred(__pc_ss2, kStunUsrName, kStunPwd));
+ BAIL_IF_ERR(tnet_turn_session_prepare(__pc_ss2));
+ BAIL_IF_ERR(tnet_turn_session_start(__pc_ss2));
+
+ BAIL_IF_ERR(tnet_turn_session_allocate(__pc_ss1));
+ BAIL_IF_ERR(tnet_turn_session_allocate(__pc_ss2));
+
+ TSK_DEBUG_INFO("*** Press ENTER to continue ***");
+ getchar();
+
+bail:
+ TSK_OBJECT_SAFE_FREE(__pc_ss1);
+ TSK_OBJECT_SAFE_FREE(__pc_ss2);
+}
+
+
+static void test_stun()
+{
+ //test_stun_parser();
+ test_turn_session();
+}
+
+#endif /* TNET_TEST_STUN_H */
diff --git a/tinyNET/test/test_tls.h b/tinyNET/test/test_tls.h
new file mode 100644
index 0000000..48ae865
--- /dev/null
+++ b/tinyNET/test/test_tls.h
@@ -0,0 +1,105 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_TLS_H
+#define TNET_TEST_TLS_H
+
+#define TEST_TLS_REMOTE_IP "192.168.16.225"
+#define TEST_TLS_REMOTE_PORT 4061
+
+#define TLS_TEST_SIP_MESSAGE \
+ "REGISTER sip:micromethod.com SIP/2.0\r\n" \
+ "Via: SIP/2.0/%s %s:%d;rport;branch=z9hG4bK1245420841406%d\r\n" \
+ "From: <sip:mamadou@micromethod.com>;tag=29358\r\n" \
+ "To: <sip:mamadou@micromethod.com>\r\n" \
+ "Call-ID: M-fa53180346f7f55ceb8d8670f9223dbb\r\n" \
+ "CSeq: 201 REGISTER\r\n" \
+ "Max-Forwards: 70\r\n" \
+ "Contact: <sip:mamadou@%s:%d;transport=%s>\r\n" \
+ "Expires: 10\r\n" \
+ "\r\n"
+
+static int tnet_tls_cb(const tnet_transport_event_t* e)
+{
+ switch(e->type){
+ case event_data:
+ {
+ TSK_DEBUG_INFO("--- TLS ---\n%s\n", (const char*)e->data);
+ break;
+ }
+ case event_closed:
+ case event_connected:
+ default:
+ {
+ break;
+ }
+ }
+ return 0;
+}
+
+
+void test_tls()
+{
+ tnet_transport_handle_t *transport = tnet_transport_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_tls_ipv4, "TLS/IPV4 TRANSPORT");
+
+ tnet_ip_t ip;
+ tnet_port_t port;
+ tnet_fd_t fd = TNET_INVALID_FD;
+
+ if(tnet_transport_start(transport)){
+ TSK_DEBUG_ERROR("Failed to create %s.", tnet_transport_get_description(transport));
+ return;
+ }
+
+ /* Set our callback function */
+ tnet_transport_set_callback(transport, tnet_tls_cb, "callbackdata");
+
+
+
+ /* Connect to the SIP Registrar */
+ if((fd = tnet_transport_connectto_2(transport, TEST_TLS_REMOTE_IP, TEST_TLS_REMOTE_PORT)) == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Failed to connect %s.", tnet_transport_get_description(transport));
+ return;
+ }
+
+ if(tnet_sockfd_waitUntilWritable(fd, TNET_CONNECT_TIMEOUT)){
+ TSK_DEBUG_ERROR("%d milliseconds elapsed and the socket is still not connected.", TNET_CONNECT_TIMEOUT);
+ tnet_transport_remove_socket(transport, &fd);
+ return;
+ }
+
+ /* Send our SIP message */
+ {
+ char* message = 0;
+ tnet_transport_get_ip_n_port(transport, fd, &ip, &port);
+ tsk_sprintf(&message, TLS_TEST_SIP_MESSAGE, "TLS", ip, port, port, ip, port, "tls");
+
+ if(!tnet_transport_send(transport, fd, message, strlen(message)))
+ {
+ TSK_DEBUG_ERROR("Failed to send data using TCP/IPv4 transport.");
+ TSK_FREE(message);
+ return;
+ }
+ TSK_FREE(message);
+ }
+
+ TSK_OBJECT_SAFE_FREE(transport);
+}
+
+#endif /* TNET_TEST_TLS_H */
+
diff --git a/tinyNET/test/test_transport.h b/tinyNET/test/test_transport.h
new file mode 100644
index 0000000..b52b554
--- /dev/null
+++ b/tinyNET/test/test_transport.h
@@ -0,0 +1,217 @@
+/* Copyright (C) 2014 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO 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 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO 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 General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef TNET_TEST_TRANSPORT_H
+#define TNET_TEST_TRANSPORT_H
+
+//#define REMOTE_IP4 "proxy.sipthor.net"//"192.168.0.15"
+#define REMOTE_IP4 "192.168.0.13"
+#define REMOTE_IP6 "2a01:e35:8632:7050:6122:2706:2124:32cb"
+#define REMOTE_IP REMOTE_IP4
+#define REMOTE_PORT 5083
+
+#if defined(ANDROID) /* FIXME */
+# define LOCAL_IP4 "10.0.2.15"
+#else
+# define LOCAL_IP4 TNET_SOCKET_HOST_ANY
+#endif
+#define LOCAL_IP6 TNET_SOCKET_HOST_ANY
+
+#if defined(ANDROID)
+# define LOCAL_PORT 5060
+#else
+# define LOCAL_PORT TNET_SOCKET_PORT_ANY
+#endif
+
+#define SIP_MESSAGE \
+ "REGISTER sip:micromethod.com SIP/2.0\r\n" \
+ "Via: SIP/2.0/%s %s:%d;rport;branch=z9hG4bK1245420841406%d\r\n" \
+ "From: <sip:mamadou@micromethod.com>;tag=29358\r\n" \
+ "To: <sip:mamadou@micromethod.com>\r\n" \
+ "Call-ID: M-fa53180346f7f55ceb8d8670f9223dbb\r\n" \
+ "CSeq: 201 REGISTER\r\n" \
+ "Max-Forwards: 70\r\n" \
+ "Contact: <sip:mamadou@%s:%d;transport=%s>\r\n" \
+ "Expires: 10\r\n" \
+ "\r\n"
+
+
+static int tnet_tcp_cb(const tnet_transport_event_t* e)
+{
+ switch(e->type){
+ case event_data:
+ {
+ TSK_DEBUG_INFO("--- TCP ---\n%s\n", (const char*)e->data);
+ break;
+ }
+ case event_closed:
+ case event_connected:
+ default:
+ {
+ break;
+ }
+ }
+ return 0;
+}
+
+static int tnet_udp_cb(const tnet_transport_event_t* e)
+{
+ switch(e->type){
+ case event_data:
+ {
+ TSK_DEBUG_INFO("--- UDP ---\n%s\n", (const char*)e->data);
+ break;
+ }
+ case event_closed:
+ case event_connected:
+ default: break;
+
+ }
+ return 0;
+}
+
+void test_transport_tcp_ipv4(tnet_transport_handle_t *transport)
+{
+ //tnet_socket_type_t type = tnet_socket_type_tcp_ipv4;
+ tnet_ip_t ip;
+ tnet_port_t port;
+ tnet_fd_t fd = TNET_INVALID_FD;
+
+ /* Set our callback function */
+ tnet_transport_set_callback(transport, tnet_tcp_cb, "callbackdata");
+
+ if(tnet_transport_start(transport)){
+ TSK_DEBUG_ERROR("Failed to create %s.", tnet_transport_get_description(transport));
+ return;
+ }
+
+ /* Connect to the SIP Registrar */
+ if((fd = tnet_transport_connectto_2(transport, REMOTE_IP, REMOTE_PORT)) == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Failed to connect %s.", tnet_transport_get_description(transport));
+ return;
+ }
+
+ if(tnet_sockfd_waitUntilWritable(fd, TNET_CONNECT_TIMEOUT)){
+ TSK_DEBUG_ERROR("%d milliseconds elapsed and the socket is still not connected.", TNET_CONNECT_TIMEOUT);
+ tnet_transport_remove_socket(transport, &fd);
+ return;
+ }
+
+
+ /* Send our SIP message */
+ {
+ char* message = 0;
+ tnet_transport_get_ip_n_port(transport, fd, &ip, &port);
+ tsk_sprintf(&message, SIP_MESSAGE, "TCP", ip, port, port, ip, port, "tcp");
+
+ if(!tnet_transport_send(transport, fd, message, strlen(message)))
+ {
+ TSK_DEBUG_ERROR("Failed to send data using %s.", tnet_transport_get_description(transport));
+ TSK_FREE(message);
+ return;
+ }
+ TSK_FREE(message);
+ }
+
+}
+
+
+int test_transport_udp_ipv4(tnet_transport_handle_t *transport)
+{
+ //tnet_socket_type_t type = tnet_socket_type_udp_ipv4;
+ tnet_ip_t ip;
+ tnet_port_t port;
+ tnet_fd_t fd = TNET_INVALID_FD;
+
+ /* Set our callback function */
+ tnet_transport_set_callback(transport, tnet_udp_cb, "callbackdata");
+
+ if(tnet_transport_start(transport)){
+ TSK_DEBUG_ERROR("Failed to create %s.", tnet_transport_get_description(transport));
+ return -1;
+ }
+
+ /* Connect to our SIP REGISTRAR */
+ if((fd = tnet_transport_connectto_2(transport, REMOTE_IP, REMOTE_PORT)) == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Failed to connect %s.", tnet_transport_get_description(transport));
+ //tnet_transport_shutdown(transport);
+ return -2;
+ }
+
+ if(tnet_sockfd_waitUntilWritable(fd, TNET_CONNECT_TIMEOUT)){
+ TSK_DEBUG_ERROR("%d milliseconds elapsed and the socket is still not connected.", TNET_CONNECT_TIMEOUT);
+ tnet_transport_remove_socket(transport, &fd);
+ return -3;
+ }
+
+ //tsk_thread_sleep(2000);
+
+ /* Send our SIP message */
+ /*while(1)*/{
+ char* message = 0;
+ tnet_transport_get_ip_n_port(transport, fd, &ip, &port);
+ //memset(ip, 0, sizeof(ip));
+ //memcpy(ip, "192.168.0.12", 12);
+ tsk_sprintf(&message, SIP_MESSAGE, "UDP", ip, port, port, ip, port, "udp");
+
+ if(!tnet_transport_send(transport, fd, message, strlen(message)))
+ {
+ TSK_DEBUG_ERROR("Failed to send data using %s.", tnet_transport_get_description(transport));
+ //tnet_transport_shutdown(transport);
+ TSK_FREE(message);
+ return -4;
+ }
+ TSK_FREE(message);
+ }
+
+ return 0;
+}
+
+void test_transport()
+{
+#define TEST_TCP 1
+#define TEST_UDP 0
+
+
+#if TEST_UDP
+ tnet_transport_handle_t *udp = tnet_transport_create(LOCAL_IP4, LOCAL_PORT, tnet_socket_type_udp_ipv4, "UDP/IPV4 TRANSPORT");
+ test_transport_udp_ipv4(udp);
+#endif
+
+#if TEST_TCP
+ tnet_transport_handle_t *tcp = tnet_transport_create(LOCAL_IP4, LOCAL_PORT, tnet_socket_type_tcp_ipv4, "TCP/IPV4 TRANSPORT");
+ test_transport_tcp_ipv4(tcp);
+#endif
+
+//#if defined(ANDROID)
+ tsk_thread_sleep(1000000);
+//#else
+ getchar();
+//#endif
+
+#if TEST_UDP
+ TSK_OBJECT_SAFE_FREE(udp);
+#endif
+
+#if TEST_TCP
+ TSK_OBJECT_SAFE_FREE(tcp);
+#endif
+}
+
+
+#endif /* TNET_TEST_TRANSPORT_H*/
diff --git a/tinyNET/tinyNET.pc.in b/tinyNET/tinyNET.pc.in
new file mode 100644
index 0000000..398988b
--- /dev/null
+++ b/tinyNET/tinyNET.pc.in
@@ -0,0 +1,16 @@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libdir = @libdir@
+includedir = @includedir@
+
+Name : libtinyNET
+Description : Doubango Telecom tinyNET (Networking) library
+Version : @PACKAGE_VERSION@
+Requires:
+Requires.private: tinySAK = @PACKAGE_VERSION@
+Conflicts:
+Cflags : -I${includedir}/tinynet
+Libs : -L${libdir} -ltinyNET
+Libs.private:
+
+
diff --git a/tinyNET/tinyNET.sln b/tinyNET/tinyNET.sln
new file mode 100644
index 0000000..76394ab
--- /dev/null
+++ b/tinyNET/tinyNET.sln
@@ -0,0 +1,51 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyNET", "tinyNET.vcproj", "{7522A458-92F4-4259-B906-E84C2A65D9F1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA} = {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinySAK", "..\tinySAK\tinySAK.vcproj", "{6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcproj", "{2189FB5C-B2B2-4ED2-8A78-64853B55DAD5}"
+ ProjectSection(ProjectDependencies) = postProject
+ {7522A458-92F4-4259-B906-E84C2A65D9F1} = {7522A458-92F4-4259-B906-E84C2A65D9F1}
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA} = {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ Release|Win32 = Release|Win32
+ Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Debug|Win32.Build.0 = Debug|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Release|Win32.ActiveCfg = Release|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Release|Win32.Build.0 = Release|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Debug|Win32.Build.0 = Debug|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Win32.ActiveCfg = Release|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Win32.Build.0 = Release|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {2189FB5C-B2B2-4ED2-8A78-64853B55DAD5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2189FB5C-B2B2-4ED2-8A78-64853B55DAD5}.Debug|Win32.Build.0 = Debug|Win32
+ {2189FB5C-B2B2-4ED2-8A78-64853B55DAD5}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {2189FB5C-B2B2-4ED2-8A78-64853B55DAD5}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {2189FB5C-B2B2-4ED2-8A78-64853B55DAD5}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {2189FB5C-B2B2-4ED2-8A78-64853B55DAD5}.Release|Win32.ActiveCfg = Release|Win32
+ {2189FB5C-B2B2-4ED2-8A78-64853B55DAD5}.Release|Win32.Build.0 = Release|Win32
+ {2189FB5C-B2B2-4ED2-8A78-64853B55DAD5}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tinyNET/tinyNET.tag b/tinyNET/tinyNET.tag
new file mode 100644
index 0000000..9a0cec2
--- /dev/null
+++ b/tinyNET/tinyNET.tag
@@ -0,0 +1,18105 @@
+<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
+<tagfile>
+ <compound kind="file">
+ <name>tnet_dhcp.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp/</path>
+ <filename>tnet__dhcp_8c</filename>
+ <includes id="tnet__dhcp_8h" name="tnet_dhcp.h" local="yes" imported="no">tnet_dhcp.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dhcp_ctx_t *</type>
+ <name>tnet_dhcp_ctx_create</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga4047baa7341d04b728d5884460214802</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_params_t *</type>
+ <name>tnet_dhcp_params_create</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga7d73362e75ec846e6ce440ba9178069a</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_reply_t *</type>
+ <name>tnet_dhcp_send_request</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>gafd37386ea787357f72a4c71f8f66df4f</anchor>
+ <arglist>(tnet_dhcp_ctx_t *ctx, tnet_dhcp_request_t *request)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_reply_t *</type>
+ <name>tnet_dhcp_query</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga66e173bcf5fd24b06a204be44312c56a</anchor>
+ <arglist>(tnet_dhcp_ctx_t *ctx, tnet_dhcp_message_type_t type, tnet_dhcp_params_t *params)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_params_add_code</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga9fb8994c0bb692b29ccd0454cc592bc5</anchor>
+ <arglist>(tnet_dhcp_params_t *params, tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp_ctx_def_t</name>
+ <anchorfile>tnet__dhcp_8c.html</anchorfile>
+ <anchor>aa58d75ace9326fe257d66da67933825e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp_params_def_t</name>
+ <anchorfile>tnet__dhcp_8c.html</anchorfile>
+ <anchor>a15f3b7d6540c0da1287fe092220e7dee</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp/</path>
+ <filename>tnet__dhcp_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dhcp__message_8h" name="tnet_dhcp_message.h" local="yes" imported="no">tnet_dhcp_message.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <class kind="struct">tnet_dhcp_params_s</class>
+ <class kind="struct">tnet_dhcp_ctx_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_TIMEOUT_DEFAULT</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga4c4d364928ec9c9b7c2dbc6d59187b94</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_CLIENT_PORT</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga40d19eada507a56dd275125e3b1c195c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_SERVER_PORT</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>gae5229a21da05427c690040fa34a6a2b3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_VENDOR_ID_DEFAULT</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga68fdef222cf61845b6d961766b4cf276</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_MAX_CODES</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga2e7d7c17df6e0c697014a20ab344d1a8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_MAX_MSG_SIZE</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga9489b2e11946fde982adc9f88a148e5c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_dhcp_query_discover</name>
+ <anchorfile>tnet__dhcp_8h.html</anchorfile>
+ <anchor>aedc60f87e2d0b05b0986eafe0d720322</anchor>
+ <arglist>(ctx, params)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_dhcp_query_request</name>
+ <anchorfile>tnet__dhcp_8h.html</anchorfile>
+ <anchor>a0df10b4454c97b7612cfbcb581ef684b</anchor>
+ <arglist>(ctx, params)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_dhcp_query_decline</name>
+ <anchorfile>tnet__dhcp_8h.html</anchorfile>
+ <anchor>a782749ba0da4d5e477f1e69f8483073d</anchor>
+ <arglist>(ctx, params)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_dhcp_query_release</name>
+ <anchorfile>tnet__dhcp_8h.html</anchorfile>
+ <anchor>abf827e1e98d86cf6618c5dac9c10d39d</anchor>
+ <arglist>(ctx, params)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_dhcp_query_inform</name>
+ <anchorfile>tnet__dhcp_8h.html</anchorfile>
+ <anchor>a85d77babd4233b7bc6009a312e10c326</anchor>
+ <arglist>(ctx, params)</arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp_params_s</type>
+ <name>tnet_dhcp_params_t</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga6fc1dfe6651b6c630b32fb6744a269e9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp_ctx_s</type>
+ <name>tnet_dhcp_ctx_t</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>gab40673583cd866001d0afc7db3e01e59</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp_reply_t *</type>
+ <name>tnet_dhcp_query</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga66e173bcf5fd24b06a204be44312c56a</anchor>
+ <arglist>(tnet_dhcp_ctx_t *ctx, tnet_dhcp_message_type_t type, tnet_dhcp_params_t *params)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dhcp_params_add_code</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga9fb8994c0bb692b29ccd0454cc592bc5</anchor>
+ <arglist>(tnet_dhcp_params_t *params, tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp_ctx_t *</type>
+ <name>tnet_dhcp_ctx_create</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga4047baa7341d04b728d5884460214802</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp_params_t *</type>
+ <name>tnet_dhcp_params_create</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga7d73362e75ec846e6ce440ba9178069a</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp_ctx_def_t</name>
+ <anchorfile>tnet__dhcp_8h.html</anchorfile>
+ <anchor>ae5301bee980eef0385c17c41b962aa4e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp_params_def_t</name>
+ <anchorfile>tnet__dhcp_8h.html</anchorfile>
+ <anchor>a8d6a9c960bfc72dc4226975e2ac545a2</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp_message.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp/</path>
+ <filename>tnet__dhcp__message_8c</filename>
+ <includes id="tnet__dhcp__message_8h" name="tnet_dhcp_message.h" local="yes" imported="no">tnet_dhcp_message.h</includes>
+ <includes id="tnet__dhcp_8h" name="tnet_dhcp.h" local="yes" imported="no">tnet_dhcp.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">../tnet_utils.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dhcp_message_t *</type>
+ <name>tnet_dhcp_message_create</name>
+ <anchorfile>tnet__dhcp__message_8c.html</anchorfile>
+ <anchor>adaf70c6f4ce8d349f9384427ef62769f</anchor>
+ <arglist>(tnet_dhcp_message_op_t opcode)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_request_t *</type>
+ <name>tnet_dhcp_request_create</name>
+ <anchorfile>tnet__dhcp__message_8c.html</anchorfile>
+ <anchor>aff1cfddd83d0cab8d5ae460ef6b64e72</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_message_t *</type>
+ <name>tnet_dhcp_reply_create</name>
+ <anchorfile>tnet__dhcp__message_8c.html</anchorfile>
+ <anchor>a9ecc81df46370cec3691acc48339a273</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_dhcp_message_serialize</name>
+ <anchorfile>tnet__dhcp__message_8c.html</anchorfile>
+ <anchor>adeb1e06721751ce944cb3b5b7b4fba72</anchor>
+ <arglist>(const tnet_dhcp_ctx_t *ctx, const tnet_dhcp_message_t *message)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_message_t *</type>
+ <name>tnet_dhcp_message_deserialize</name>
+ <anchorfile>tnet__dhcp__message_8c.html</anchorfile>
+ <anchor>aacd32aa714f4873545d046d96da49a2e</anchor>
+ <arglist>(const struct tnet_dhcp_ctx_s *ctx, const uint8_t *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_dhcp_option_t *</type>
+ <name>tnet_dhcp_message_find_option</name>
+ <anchorfile>tnet__dhcp__message_8c.html</anchorfile>
+ <anchor>a2b229a376755970e8ac2d2eea2c7ff24</anchor>
+ <arglist>(const tnet_dhcp_message_t *message, tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_message_add_codes</name>
+ <anchorfile>tnet__dhcp__message_8c.html</anchorfile>
+ <anchor>aed293c9712d53931456c003b566abbd4</anchor>
+ <arglist>(tnet_dhcp_message_t *self, tnet_dhcp_option_code_t codes[], unsigned codes_count)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp_message_def_t</name>
+ <anchorfile>tnet__dhcp__message_8c.html</anchorfile>
+ <anchor>a001d2d362157b75638399472c448348e</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp_message.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp/</path>
+ <filename>tnet__dhcp__message_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dhcp__option_8h" name="tnet_dhcp_option.h" local="yes" imported="no">tnet_dhcp_option.h</includes>
+ <includes id="tnet__hardwares_8h" name="tnet_hardwares.h" local="yes" imported="no">tnet_hardwares.h</includes>
+ <class kind="struct">tnet_dhcp_message_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_MESSAGE_IS_REQUEST</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>ae2e302cbcea8869129bcc91161428d81</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_MESSAGE_IS_REPLY</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>ab571915b071fb6ed6e577f8d68e0c3d6</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_MAGIC_COOKIE</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a33f88fe4e708a2afc5a2b229bf22f821</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_MESSAGE_MIN_SIZE</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>ad9883a8e753ae872d4883f561283add6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dhcp_message_type_e</type>
+ <name>tnet_dhcp_message_type_t</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a0ca808a6b2e6ae7bf7ce313f258cf346</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dhcp_message_op_e</type>
+ <name>tnet_dhcp_message_op_t</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a89d25a994f6584c738384c18de0f8090</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp_message_s</type>
+ <name>tnet_dhcp_message_t</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a659f843c5d28cdf6294fbde36667bb3e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_dhcp_messages_L_t</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>ae1f846a04b26fccc138b06cf931006ef</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_dhcp_message_t</type>
+ <name>tnet_dhcp_request_t</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a25e00e6e9184caed3b65675dfe7604f1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_dhcp_message_t</type>
+ <name>tnet_dhcp_reply_t</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a6486614e440217fbb7d794f0c160a89f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dhcp_message_type_e</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a9ad24c42adb00d70b28a7ed0b62fe905</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_type_discover</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a9ad24c42adb00d70b28a7ed0b62fe905a23945bd14286dcfe8684e72907eb8cef</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_type_offer</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a9ad24c42adb00d70b28a7ed0b62fe905a99a05a69b4ebabad25fa9ebffbd6f93f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_type_request</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a9ad24c42adb00d70b28a7ed0b62fe905a1f97becc1fd671298a8ffc840f280509</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_type_decline</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a9ad24c42adb00d70b28a7ed0b62fe905a6d1e6eb6c6f8003d9d44df59b8005472</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_type_ack</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a9ad24c42adb00d70b28a7ed0b62fe905abaf0807c55fca70088fe1c9c40616023</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_type_nack</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a9ad24c42adb00d70b28a7ed0b62fe905a1bc59be9cf0b3a33f81185bded360513</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_type_release</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a9ad24c42adb00d70b28a7ed0b62fe905a149634ef5af759448d1c351d14372c2c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_type_inform</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a9ad24c42adb00d70b28a7ed0b62fe905a508ab5b809a40af17dd020c3e18cbd78</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dhcp_message_op_e</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a1dc99290aacbbc3f78905c89a35a5e92</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_op_bootrequest</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a1dc99290aacbbc3f78905c89a35a5e92aa2edacd8fccb677b3700a851bc8b7d4a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_op_bootreply</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a1dc99290aacbbc3f78905c89a35a5e92a98bb49a25fe584d571047853182966d3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_dhcp_message_serialize</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>aad66010e56c32d932bda60f073f53fd5</anchor>
+ <arglist>(const struct tnet_dhcp_ctx_s *ctx, const tnet_dhcp_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_message_t *</type>
+ <name>tnet_dhcp_message_deserialize</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>aacd32aa714f4873545d046d96da49a2e</anchor>
+ <arglist>(const struct tnet_dhcp_ctx_s *ctx, const uint8_t *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_dhcp_option_t *</type>
+ <name>tnet_dhcp_message_find_option</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>ada261fbb37de7bc6e63a0596355a9d2c</anchor>
+ <arglist>(const tnet_dhcp_message_t *self, tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_message_add_codes</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>aed293c9712d53931456c003b566abbd4</anchor>
+ <arglist>(tnet_dhcp_message_t *self, tnet_dhcp_option_code_t codes[], unsigned codes_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp_message_t *</type>
+ <name>tnet_dhcp_message_create</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a58ad2c16d636e848c247ab618addabb3</anchor>
+ <arglist>(tnet_dhcp_message_op_t opcode)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp_request_t *</type>
+ <name>tnet_dhcp_request_create</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a58d28c4dfab786f9b53d28e15c86feeb</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp_message_t *</type>
+ <name>tnet_dhcp_reply_create</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a46fe33dfa57b8c43858b4445333851bf</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp_message_def_t</name>
+ <anchorfile>tnet__dhcp__message_8h.html</anchorfile>
+ <anchor>a90d96e17271118fc819dd15d4c6545f7</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp_option.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp/</path>
+ <filename>tnet__dhcp__option_8c</filename>
+ <includes id="tnet__dhcp__option_8h" name="tnet_dhcp_option.h" local="yes" imported="no">tnet_dhcp_option.h</includes>
+ <includes id="tnet__dhcp__option__sip_8h" name="tnet_dhcp_option_sip.h" local="yes" imported="no">tnet_dhcp_option_sip.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dhcp_option_t *</type>
+ <name>tnet_dhcp_option_create</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>a8c191e2708eb2daf4e8386fa2f638830</anchor>
+ <arglist>(tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_option_paramslist_t *</type>
+ <name>tnet_dhcp_option_paramslist_create</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>acfb7f4858abc9bc7597f43c84209ca6b</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_option_dns_t *</type>
+ <name>tnet_dhcp_option_dns_create</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>adda6aa01b12a617cee461a1406e4675d</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_option_init</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>aa86c774dfbc192fcf37731deac3009af</anchor>
+ <arglist>(tnet_dhcp_option_t *self, tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_option_deinit</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>aede9304d533f9fec7529149b345da1ae</anchor>
+ <arglist>(tnet_dhcp_option_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_option_t *</type>
+ <name>tnet_dhcp_option_deserialize</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>a4f9f1042f27b33be6150ce5a7eea09f8</anchor>
+ <arglist>(const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_option_serialize</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>a155a3fdeef17dc15f70dfe8ff41dddf7</anchor>
+ <arglist>(const tnet_dhcp_option_t *self, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_option_serializeex</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>a01c369b06ee3e99ed20ec3bcb7a1ce16</anchor>
+ <arglist>(tnet_dhcp_option_code_t code, uint8_t length, const void *value, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_option_paramslist_add_code</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>a08821769abef66cf1e459fb89ba442a2</anchor>
+ <arglist>(tnet_dhcp_option_paramslist_t *self, tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp_option_def_t</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>a3ed2f79cb57a68233ab3d5c7cbb8f6b2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp_option_paramslist_def_t</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>ace02e02ac52286b3f0e8894e54d51f25</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp_option_dns_def_t</name>
+ <anchorfile>tnet__dhcp__option_8c.html</anchorfile>
+ <anchor>abaf0ca973a723dea4becaaa62b28340f</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp_option.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp/</path>
+ <filename>tnet__dhcp__option_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <class kind="struct">tnet_dhcp_option_s</class>
+ <class kind="struct">tnet_dhcp_option_paramslist_s</class>
+ <class kind="struct">tnet_dhcp_option_dns_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_OPTION</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>aaaecef93a24661e93b845cff3e739374</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DECLARE_DHCP_OPTION</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a1215ccb86d8d3db9fb79e490e07a32e1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dhcp_option_code_e</type>
+ <name>tnet_dhcp_option_code_t</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a0d884b63b7233a9e16b0403d57601832</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp_option_s</type>
+ <name>tnet_dhcp_option_t</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a8309fe5e24a8dd2452e8f94e6ddf9903</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_dhcp_options_L_t</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a38aa38901b7e776af2652fc15fa55356</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp_option_paramslist_s</type>
+ <name>tnet_dhcp_option_paramslist_t</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>af36405ef3b15a68849ef0660905e0973</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp_option_dns_s</type>
+ <name>tnet_dhcp_option_dns_t</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a142e55f732f165a5c5148d62cf920647</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dhcp_option_code_e</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Pad</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a3db16c179b4e803c4727c6e06da3176a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Subnet_Mask</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a22afaeba4902bd5b93252d8f7565d91e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Time_Offset</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267acb1125be7938317663790fd5abdad638</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Router</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a53d4594993d9fa1333144da093207ca9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Time_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267aa9014537e2e713c7445c469d8742e00e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Name_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a9e227834898d7fd25765c893ad57311d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Domain_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a455ac19797e8925d54828634afc57e53</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Log_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ae134f18d7811269d06871af23e124690</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Quotes_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ad2d3ef93abecf2ec87b6bc732fa9ff7b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_LPR_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267afa6659c124ebe18b68bebf56d1a99606</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Impress_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267adc43d7c842dca6214876b2335f7ebf7d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_RLP_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ab47d13b0b5f234c20b1fd8594e903054</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Hostname</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267acddef5f414494943a3dccf5f1c60b622</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Boot_File_Size</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a1df26a2b2ba9a101b4722c07a95ad8b8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Merit_Dump_File</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a9485cc76a7f5a955f6c557e39949e936</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Domain_Name</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a5e722990c22229b122cc82ef9a6860f1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Swap_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267aae77ca18e62d574a8ce3cb8b0c41306d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Root_Path</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a17c525c0f329ea844e2949047c9cf3c4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Extension_File</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ae53b005959bb221f8a987a12b229607e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Forward_On_Off</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a01a678dee4780da54ba84a927a226c2d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_SrcRte_On_Off</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a11c4aa754009c765dca9af0d38354d83</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Policy_Filter</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267aa639ce27b22dd94f73230254fa5e614b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Max_DG_Assembly</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a6c8e408e641f168d0e16d6bf9f73a86b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Default_IP_TTL</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a172d60b4d8b665c640cc0e6d8d1ee4f1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_MTU_Timeout</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267afd57e8f5523a60577f9f28929a96b5af</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_MTU_Plateau</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a6da75f842ab197b0dce33099a6c8b9a9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_MTU_Interface</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267acc58dcea43623cb816a8d3aeb76b5ef1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_MTU_Subnet</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a7f0c5784c9c6c09beb001420c9dcd27b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Broadcast_Address</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a1549b63a5d3d29b1bb1cc2edb244727b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Mask_Discovery</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac83c18e46a5eda9312734480a87052e1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Mask_Supplier</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ae664fa2f96f74afa2d4b06b630df3918</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Router_Discovery</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a3c7e0a7996a56850372085eeb17cb05b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Router_Request</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267adfa5bf99208f509c29482af852e947e8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Static_Route</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a69ae5b7e45a10e01ec6ed2bfc3c5d432</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Trailers</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267af9afedc6aae1478dddf221cb50ff5e90</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_ARP_Timeout</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267af695b120918d3b6184496e4f8dfbd08d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Ethernet</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a6c4d8483ef2919f61d483ca148373fe2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Default_TCP_TTL</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a2e040e5f455dbf8f0e58ce211d008b2e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Keepalive_Time</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ab7c01bb939de46cebcf2fd59f4681c9a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Keepalive_Data</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a4848cd5b247e19a53e25b8b19f0cda79</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NIS_Domain</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a61b2484e865d87160c2fdc57f4d9cf26</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NIS_Servers</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a3d38266d6255cc2758c7835c14dc4e64</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NTP_Servers</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a9f6393d845be5470b70541a8b0d61f6b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Vendor_Specific</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a1a117c6bf7e8529e47f15b7bb98134c0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NETBIOS_Name_Srv</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a0a6dab62f4b3dbef55cd463baddcfbc1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NETBIOS_Dist_Srv</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267aa32205b2ce09e43636610da33af3f67a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NETBIOS_Node_Type</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a7f147e4d047d2520d72d112a982051a9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NETBIOS_Scope</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac81ec528c4853567162a84d927201989</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_X_Window_Font</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a1029f12f49c85b6632334bfa50c41470</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_X_Window_Manager</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac9f843f778dec2ea8c9a3448878de16a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Address_Request</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ad907c2d58a9105c09cadff20dd637cdf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Address_Time</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ab6c1afaf4d45ffd3a7cba7a89a2b3842</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Overload</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a1ae58715af5dc64d31636b52e8e1c9b6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_DHCP_Msg_Type</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267aec311da2af406a328f277b0f2fb3a82f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_DHCP_Server_Id</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a55b2feac2916ca0359a166cd181f90b2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Parameter_List</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac8f3b4449ccfb57512bcf8512d8e6bc8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_DHCP_Error_Message</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a6087dafa9de89a09e86673cf911401ba</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_DHCP_Max_Msg_Size</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a8eec205b20430ae6ceb30e6c0f6f7821</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Renewal_Time</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a22bb26a2d3bb13080d4e60d36629de84</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Rebinding_Time</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac93fb941a9a459ac948a04bc7d7046ea</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Class_Id</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ab718f2a66a86656d0b7a0a0054debef4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Client_Id</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a3a053d95af35d07fd6b89fa221ecb25f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NetWare_IP_Domain</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a9debdf18426621bd3fa7766a1232f92b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NetWare_IP_Option</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a3869b8054427578ddeb921307152709b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NIS_Domain_Name</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac5052d4f68689bfb4ed19aa48a199031</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NIS_Server_Addr</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a1bbc999cc35cdaa528f6917e232ced1e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Server_Name</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a12b8f8d1b8ef85c2b7ae1ceeccaaedf9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Bootfile_Name</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267abfdc7bfff9ec4ce7f31c70ebe998b954</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Home_Agent_Addrs</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a25976b54480f46182a27685193166544</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_SMTP_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a18acd1ebc079947540d8510028ade9c2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_POP3_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267aea60603b068a1e9c3092935a46a35620</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NNTP_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267aa39ab80643b0d53856642e7bcb08e851</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_WWW_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ad6e4eaae6c03142e9cf34c5dcce1c9b9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Finger_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a26997d21c22819aa026f17931526c3fc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_IRC_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ab4f06c56ebc8542ff036874462fa06cf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_StreetTalk_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a2c2a9461ead25b638470d117f62c693c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_STDA_Server</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a90bb3aa3d636f453b814e62f6b01afa2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_User_Class</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac2d94d8867208f0b7dd7db0c8f4f0410</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Directory_Agent</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267addf51622995424216a5c9b093a09690d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Service_Scope</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a490bfcb5b1edc4d38e889445b2bae438</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Rapid_Commit</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a57eef60d953036aa71ca0f86f503277c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Client_FQDN</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ab71fc6aa6acd194b6168fd90d9416b79</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Relay_Agent_Information</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac9e7b477c65828c675aa983550f20708</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_iSNS</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267af3056722f57c9e2deb11b7ac89bc6aad</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NDS_Servers</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267af38d03ef84426035e4e98b0b150f67a4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NDS_Tree_Name</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a6d5e0fd3c4e10ee5ca759f580df85379</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_NDS_Context</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267adda2c9999a502bcbea1a2d939c83722a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_BCMCS_Controller_Domain_Name_list</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a309d59bc829f89e327d564ca83f9ea35</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_BCMCS_Controller_IPv4_address_option</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a26fb514ac58a40a4e929125ddf8444a0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Authentication</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267aebc20bbbd856ecf20e83bcc686ce9d47</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_client_last_transaction_time</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a816b14a051325d9f932ff4716756f800</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_associated_ip</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a43d2e59cb8d933a8572342c8b6d866ec</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Client_System</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a37af94707d0f562976bfc6317c43bde2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Client_NDI</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267af147b15ea7029f0bbb947826e8b814a6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_LDAP</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267adaaf1df2b4fbef075fb785a8711dea01</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_REMOVED_Unassigned</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a1fa630140e4d92299c63be6d10781105</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_UUID_GUID</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ad7588ad44a5224ae76b821b7c62bb07b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_User_Auth</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267acd1fe71d641ec7dfcdb33ed9f43e66da</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_GEOCONF_CIVIC</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a52bdfbace1a1b2934fc0811dcfa06f68</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_PCode</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a21d49fa0ae4548d7af0f95baa07ac017</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_TCode</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a10bc22328c68c3000cf8d7b1628818b6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Netinfo_Address</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a78bc5859b268bcc2d3545c8f5dfbae96</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Netinfo_Tag</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ae887e6c0a82fb5ec307065228c51c790</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a52bc7b00fd1d68b5dc04151c326e0818</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Auto_Config</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267adbacec91caecd4a7fbe7e101b9ab6d2c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Name_Service_Search</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a523555ccbf327ecff12b085ae5d7db3a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Subnet_Selection_Option</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a29bd9fe0badcd3468055ce6cdae92a24</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Domain_Search</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a80cba2bedb41e20701ae27ace44ad477</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_SIP_Servers_DHCP_Option</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a22345c46a4d62c70d3b1339e581a3731</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Classless_Static_Route_Option</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267aa388f714c3767f8c9a86e48d7d525b4b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_CCC</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a1ad3a007b2b9cbad13ba5a008b3ec0df</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_GeoConf_Option</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a906df978c0c2f24cb8f5336e1b914d23</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_V_I_Vendor_Class</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a8ad8e03ea332ead5aa48ce48bf2be268</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_V_I_Vendor_Specific_Information</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a1a93a89cce7f5de694b59d18e970318e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Etherboot_signature</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a76811d968f0658217813a3f03f301821</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_DOCSIS</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a4ba4c7001da4ee3c95ce6c881fca4d91</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_TFTP_Server_IP</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a13bd9cc98ebc3ecc966ee435816795c3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Kernel_options</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a0cd77d0466916c4dc19d382d3b31640b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Call_Server_IP</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ae7888f655111c7372d59fb3b678173ec</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Ethernet_interface</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267abc32b875f56efbd40f3012886e274144</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Discrimination</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a38daa9f7725d36d4a2815f2f00653942</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Remote_statistics_server_IP</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a301449c7264ff3ebaf8ecd8ac0319acb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_IEEE_802_1Q_VLAN_ID</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a570b3c33b9673eae85a2c6606f554d4c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_IEEE_802_1D_p</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a69a488af2129f44b5bf4a857b2121c53</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_DSCP</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a6eba8281d22872a7399ef0a251dc45c1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_HTTP_Proxy</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a8a3dbcbf519c72394a53ae0f8a2550c8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_OPTION_PANA_AGENT</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a7eda4742b715b5ea197c7b34437e90a6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_OPTION_V4_LOST</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a5619ebc89deebdb25f555edb9f9a9ad7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_OPTION_CAPWAP_AC_V4</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a3eb6db2d74930e5a1491566009ceb455</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_OPTION_IPv4_Address_MoS</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a86da375324b341191ef9d26b17c9b3f3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_OPTION_IPv4_FQDN_MoS</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a12103feb04edb440553a019d355acdd4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_TFTP_server_address</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267afa0c82213301d607a4d9a2c96f455637</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Etherboot</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac5a27f085ec2c7f16344780104ea594a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_GRUB_configuration_path_name</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac85874f026b1900e5b4d49c7b81b5324</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_IP_Telephone</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a3cc7dd46e6f5c867f73ffdd8b63075a8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_PacketCable_and_CableHome</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a7a523e971005cd539de416bf08f808e6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_PXELINUX_Magic</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a1be705d680c1dfb50a4028aa97b1a57d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Configuration_File</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267aab40cb17d9a5b3a08b606e2689b4c3c3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Path_Prefix</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267ac454853cf81c135e7ba5120dab807b8f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Reboot_Time</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a987d24bb1c47b0a2e1104e4a1eae40d2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Subnet_Allocation</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267af600259f2b6bf657860363d3ff54a36e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_Virtual_Subnet</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a9a5537489715198359224a72a8333f5a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_null</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a5248003e467b342ad8d367d77c03a102</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp_code_End</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ae8a9751325d4773a0a83f3b9acd1c267a57f24581049c7b6b50678bedf5d1e18b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_option_init</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>aa86c774dfbc192fcf37731deac3009af</anchor>
+ <arglist>(tnet_dhcp_option_t *self, tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_option_deinit</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>aede9304d533f9fec7529149b345da1ae</anchor>
+ <arglist>(tnet_dhcp_option_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_option_t *</type>
+ <name>tnet_dhcp_option_deserialize</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a4f9f1042f27b33be6150ce5a7eea09f8</anchor>
+ <arglist>(const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_option_serialize</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a155a3fdeef17dc15f70dfe8ff41dddf7</anchor>
+ <arglist>(const tnet_dhcp_option_t *self, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_option_serializeex</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a01c369b06ee3e99ed20ec3bcb7a1ce16</anchor>
+ <arglist>(tnet_dhcp_option_code_t code, uint8_t length, const void *value, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_option_paramslist_add_code</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a08821769abef66cf1e459fb89ba442a2</anchor>
+ <arglist>(tnet_dhcp_option_paramslist_t *self, tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp_option_t *</type>
+ <name>tnet_dhcp_option_create</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>ab9c6dfc8352393b8052b651930c1a417</anchor>
+ <arglist>(tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp_option_paramslist_t *</type>
+ <name>tnet_dhcp_option_paramslist_create</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a2b702a769d6ec8e978fbf96883f16702</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp_option_dns_t *</type>
+ <name>tnet_dhcp_option_dns_create</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a1b1f05e525002a7604ae09b3a93c4392</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp_option_def_t</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a4375d338dbe4882ff1e4b6f50a5930c8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_ns_def_t</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a848fe1ef765215af38d449d4b0fd5943</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp_option_paramslist_def_t</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a4188002caa3f5d304c2fc8d05f12ff95</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp_option_dns_def_t</name>
+ <anchorfile>tnet__dhcp__option_8h.html</anchorfile>
+ <anchor>a5fb79a339ebd4e5f8d3f4a660a1e1b5d</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp_option_sip.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp/</path>
+ <filename>tnet__dhcp__option__sip_8c</filename>
+ <includes id="tnet__dhcp__option__sip_8h" name="tnet_dhcp_option_sip.h" local="yes" imported="no">tnet_dhcp_option_sip.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">dns/tnet_dns_rr.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dhcp_option_sip_t *</type>
+ <name>tnet_dhcp_option_sip_create</name>
+ <anchorfile>tnet__dhcp__option__sip_8c.html</anchorfile>
+ <anchor>ae86d8d7fc2165ad48e3b0045d9a46741</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp_option_sip_def_t</name>
+ <anchorfile>tnet__dhcp__option__sip_8c.html</anchorfile>
+ <anchor>a52f05e713d97bbab043093691ffb7b5c</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp_option_sip.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp/</path>
+ <filename>tnet__dhcp__option__sip_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dhcp__option_8h" name="tnet_dhcp_option.h" local="yes" imported="no">tnet_dhcp_option.h</includes>
+ <class kind="struct">tnet_dhcp_option_sip_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dhcp_option_sip_s</type>
+ <name>tnet_dhcp_option_sip_t</name>
+ <anchorfile>tnet__dhcp__option__sip_8h.html</anchorfile>
+ <anchor>a39b62ac1f962ef42faaa1243c19d0700</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp_option_sip_t *</type>
+ <name>tnet_dhcp_option_sip_create</name>
+ <anchorfile>tnet__dhcp__option__sip_8h.html</anchorfile>
+ <anchor>a987bc86af29c0bf1f00f6af77c6a9794</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp_option_sip_def_t</name>
+ <anchorfile>tnet__dhcp__option__sip_8h.html</anchorfile>
+ <anchor>a722bd3581d65a608a7eec06a40920992</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp6.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6/</path>
+ <filename>tnet__dhcp6_8c</filename>
+ <includes id="tnet__dhcp6_8h" name="tnet_dhcp6.h" local="yes" imported="no">tnet_dhcp6.h</includes>
+ <member kind="function">
+ <type>tnet_dhcp6_ctx_t *</type>
+ <name>tnet_dhcp6_ctx_create</name>
+ <anchorfile>tnet__dhcp6_8c.html</anchorfile>
+ <anchor>a65328f23502499947219f80b285349b0</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_reply_t *</type>
+ <name>tnet_dhcp6_send_request</name>
+ <anchorfile>group__tnet__dhcp6__group.html</anchorfile>
+ <anchor>gadac4a203c542c67bcd608974944ade8d</anchor>
+ <arglist>(const tnet_dhcp6_ctx_t *ctx, tnet_dhcp6_request_t *request)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_reply_t *</type>
+ <name>tnet_dhcp6_requestinfo</name>
+ <anchorfile>group__tnet__dhcp6__group.html</anchorfile>
+ <anchor>gac8dd99f4e54866bbdf190ce5061b5b3a</anchor>
+ <arglist>(const tnet_dhcp6_ctx_t *ctx, const tnet_dhcp6_option_orequest_t *orequest)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_ctx_def_t</name>
+ <anchorfile>tnet__dhcp6_8c.html</anchorfile>
+ <anchor>aedef4f922e3c639b6bcbf4625f347050</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp6.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6/</path>
+ <filename>tnet__dhcp6_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dhcp6__message_8h" name="tnet_dhcp6_message.h" local="yes" imported="no">tnet_dhcp6_message.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <class kind="struct">tnet_dhcp6_ctx_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_VENDOR_CLASS_DATA_DEFAULT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a77a47e057fcd3feee6a6ea6ca67be5a3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_All_DHCP_Relay_Agents_and_Servers</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>aba226ab3184b0eeb37fd2cd175993af0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_All_DHCP_Servers</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a3daf3c978170cc4d1c3efa71704bdffb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_SOL_MAX_DELAY</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>ac7651259caa112f43790703a8d982957</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_SOL_TIMEOUT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>acd358db10e5574bacf05dd459a80669a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_SOL_MAX_RT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a8d86fe584a433bf33683590b92b472f5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REQ_TIMEOUT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>ac73b545aaf7be2d2508ef5c4a4dbbcba</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REQ_MAX_RT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a4e30fbce41200c6c8948f11108d945d5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REQ_MAX_RC</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>ac63784bde12e796094e5c7c574cad858</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_CNF_MAX_DELAY</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a705366e8798017d5a91cf672ecd427cc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_CNF_TIMEOUT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a88918fd42ad5bdad2ee38c647eb9ab55</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_CNF_MAX_RT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a05b88aad73b2fdd90877a7d8b12c6e17</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_CNF_MAX_RD</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a0beba10b142e2504854d5e6b745d637c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REN_TIMEOUT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a9b642dc3551499424e4ccb5fd7de1a87</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REN_MAX_RT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>aad8e25c55996b4b539415572040509bb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REB_TIMEOUT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a62c4bbc046ae2586dc53c87dbad79354</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REB_MAX_RT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>ab5db7aad6ff064b544ce449f2041f2d3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_INF_MAX_DELAY</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>ab0c98c0588182dcc5659b6d2b6d60742</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_INF_TIMEOUT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a2a5bc3707cd31848a9e8d17786b3b9b7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_INF_MAX_RT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>afce91c3c151c45351e44fa6a84620321</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REL_TIMEOUT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a51722f784ecd9892c789c5a68d230db5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REL_MAX_RC</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a0269ce1104f8f96dbf7d28b70135c4fa</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_DEC_TIMEOUT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a2bd1d5297f92edbdd1537df9fadd2d8a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_DEC_MAX_RC</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>aa378cfd76fb91722de7c82dc149b9351</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REC_TIMEOUT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a2e5f4d83b55504ac3176a030530920bd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_REC_MAX_RC</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>aef253c7ac2234bf2fd261a3713575d9b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_RT_HOP_COUNT_LIMIT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>aa42aa205bd76ebe8eb41499de2fddc6c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_TIMEVAL_INFINITY</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>abde3fc1a4d5a887fb742215832866018</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_CLIENT_PORT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a102edccd001f74ce44438d0b7836d4eb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_SERVER_PORT</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a8088025204cff9dc319aa02f0e448a94</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_ctx_s</type>
+ <name>tnet_dhcp6_ctx_t</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>aa5ef731f53320126a141fcf6e6ff244e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_reply_t *</type>
+ <name>tnet_dhcp6_requestinfo</name>
+ <anchorfile>group__tnet__dhcp6__group.html</anchorfile>
+ <anchor>gac8dd99f4e54866bbdf190ce5061b5b3a</anchor>
+ <arglist>(const tnet_dhcp6_ctx_t *ctx, const tnet_dhcp6_option_orequest_t *orequest)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_ctx_t *</type>
+ <name>tnet_dhcp6_ctx_create</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a356d67baebf7f38649454a27dac20983</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_ctx_def_t</name>
+ <anchorfile>tnet__dhcp6_8h.html</anchorfile>
+ <anchor>a4b2db90770aebf579b3c4413ec5e0afd</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp6_duid.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6/</path>
+ <filename>tnet__dhcp6__duid_8c</filename>
+ <includes id="tnet__dhcp6__duid_8h" name="tnet_dhcp6_duid.h" local="yes" imported="no">tnet_dhcp6_duid.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_duid_llt_serialize</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>a6158e8d5f12ebb59d063aaa2188b8c88</anchor>
+ <arglist>(const tnet_dhcp6_duid_llt_t *self, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_duid_en_serialize</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>a49faf9f7df8f9bec56a7513d80760bbf</anchor>
+ <arglist>(const tnet_dhcp6_duid_en_t *self, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_duid_ll_serialize</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>ad3b89b93ceb86c6eefb69edb4c4e0468</anchor>
+ <arglist>(const tnet_dhcp6_duid_ll_t *self, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_duid_llt_t *</type>
+ <name>tnet_dhcp6_duid_llt_create</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>ad669e57db28c397394675192c5491045</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_duid_en_t *</type>
+ <name>tnet_dhcp6_duid_en_create</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>a9676e3d562b936c4527404cc2f7efff9</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_duid_ll_t *</type>
+ <name>tnet_dhcp6_duid_ll_create</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>ab0782d8fce2411236be32df83653c626</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_duid_init</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>a77fedc7d6fdba85f14b495e79cbc49a2</anchor>
+ <arglist>(tnet_dhcp6_duid_t *self, tnet_dhcp6_duid_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_duid_deinit</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>a300a2a4fd5176167fdb36690e56614a8</anchor>
+ <arglist>(tnet_dhcp6_duid_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_duid_t *</type>
+ <name>tnet_dhcp6_duid_deserialize</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>a3199da6b9c0b69f3624797ca453b34a8</anchor>
+ <arglist>(const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_duid_serialize</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>a9e5ba71e2a4e5d7e97fe1a5638ff49d7</anchor>
+ <arglist>(const tnet_dhcp6_duid_t *self, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_duid_llt_def_t</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>a6272c96c0db70f87dfd83fa2830b1293</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_duid_en_def_t</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>a00e01ddd6f88a34736506ecf3e61cefe</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_duid_ll_def_t</name>
+ <anchorfile>tnet__dhcp6__duid_8c.html</anchorfile>
+ <anchor>adace29407e9d71220f2c226413e06f00</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp6_duid.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6/</path>
+ <filename>tnet__dhcp6__duid_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__hardwares_8h" name="tnet_hardwares.h" local="yes" imported="no">tnet_hardwares.h</includes>
+ <class kind="struct">tnet_dhcp6_duid_s</class>
+ <class kind="struct">tnet_dhcp6_duid_llt_s</class>
+ <class kind="struct">tnet_dhcp6_duid_en_s</class>
+ <class kind="struct">tnet_dhcp6_duid_ll_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_DUID</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>ab4c6f2cd628bd38f47a2b1ee40cbd0ea</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_DUID_LLT</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>ae98050166aa26df3653f93a294a9f050</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_DUID_EN</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a414aa40eb67f6d0fd897d35558068d4c</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_DUID_LL</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a6dcc472aadbac1899c34516d268e2e53</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DECLARE_DHCP6_DUID</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>aecb22b4bb4e7cfa73066e7e24fa273bd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dhcp6_duid_type_e</type>
+ <name>tnet_dhcp6_duid_type_t</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a6ace50507f0d1ff6a3d11ad7a3abcc45</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_duid_s</type>
+ <name>tnet_dhcp6_duid_t</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>ac98eadf10c17c6e565659d1ca092ce2b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_dhcp6_duids_L_t</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a2ad6d664409b477704d224683c27c637</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_duid_llt_s</type>
+ <name>tnet_dhcp6_duid_llt_t</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a4588ecc95aef0ad9aef18c98f434e30a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_duid_en_s</type>
+ <name>tnet_dhcp6_duid_en_t</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>aa2bd03ce3ce8d569d40613c1acfe2eb9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_duid_ll_s</type>
+ <name>tnet_dhcp6_duid_ll_t</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a1ea496b636bc7aad4c75421a88c07304</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dhcp6_duid_type_e</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>ae4487e952ac42c84e59514abd6b42fca</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_duid_linklayer_plus_time</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>ae4487e952ac42c84e59514abd6b42fcaaf8d0386e94677b1e9ebddb38af60c0e3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_duid_Vendor_assigned_id</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>ae4487e952ac42c84e59514abd6b42fcaab9178b2917c5cea836d2139dc30074c3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_duid_linklayer</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>ae4487e952ac42c84e59514abd6b42fcaaad211ab6478327692901e93bad0ae975</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_duid_init</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a77fedc7d6fdba85f14b495e79cbc49a2</anchor>
+ <arglist>(tnet_dhcp6_duid_t *self, tnet_dhcp6_duid_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_duid_deinit</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a300a2a4fd5176167fdb36690e56614a8</anchor>
+ <arglist>(tnet_dhcp6_duid_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_duid_t *</type>
+ <name>tnet_dhcp6_duid_deserialize</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a3199da6b9c0b69f3624797ca453b34a8</anchor>
+ <arglist>(const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_duid_serialize</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a9e5ba71e2a4e5d7e97fe1a5638ff49d7</anchor>
+ <arglist>(const tnet_dhcp6_duid_t *self, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_duid_llt_t *</type>
+ <name>tnet_dhcp6_duid_llt_create</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>af6415090eae08032278ca9bbc9cb05a6</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_duid_en_t *</type>
+ <name>tnet_dhcp6_duid_en_create</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a6ffd8bf8ee46ce8ffc113d0ace87aaf1</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_duid_ll_t *</type>
+ <name>tnet_dhcp6_duid_ll_create</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>ae87a2c797c94c599aa338d7e9968a218</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_duid_llt_def_t</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>ad547787afd9e2da4814a0d1521d4f0ed</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_duid_en_def_t</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>ab238a01b1746af439c0bb24454461929</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_duid_ll_def_t</name>
+ <anchorfile>tnet__dhcp6__duid_8h.html</anchorfile>
+ <anchor>a023c6eeebfc906ffc76746420d96dcf7</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp6_message.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6/</path>
+ <filename>tnet__dhcp6__message_8c</filename>
+ <includes id="tnet__dhcp6__message_8h" name="tnet_dhcp6_message.h" local="yes" imported="no">tnet_dhcp6_message.h</includes>
+ <includes id="tnet__dhcp6_8h" name="tnet_dhcp6.h" local="yes" imported="no">tnet_dhcp6.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dhcp6_message_t *</type>
+ <name>tnet_dhcp6_message_create</name>
+ <anchorfile>tnet__dhcp6__message_8c.html</anchorfile>
+ <anchor>a2fc793a413bfb883283381f34af6fbc6</anchor>
+ <arglist>(tnet_dhcp6_message_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_request_t *</type>
+ <name>tnet_dhcp6_request_create</name>
+ <anchorfile>tnet__dhcp6__message_8c.html</anchorfile>
+ <anchor>ae36dd840f14b603a475783ef25c76810</anchor>
+ <arglist>(tnet_dhcp6_message_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_dhcp6_message_serialize</name>
+ <anchorfile>tnet__dhcp6__message_8c.html</anchorfile>
+ <anchor>a9e395202fd1e6d0c6ba0c55682540c3d</anchor>
+ <arglist>(const tnet_dhcp6_ctx_t *ctx, const tnet_dhcp6_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_message_t *</type>
+ <name>tnet_dhcp6_message_deserialize</name>
+ <anchorfile>tnet__dhcp6__message_8c.html</anchorfile>
+ <anchor>a49db33d334a348c07b63a482690ac5ec</anchor>
+ <arglist>(const tnet_dhcp6_ctx_t *ctx, const uint8_t *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_message_def_t</name>
+ <anchorfile>tnet__dhcp6__message_8c.html</anchorfile>
+ <anchor>a11a2de3d84357d63c0f4908c458f975a</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp6_message.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6/</path>
+ <filename>tnet__dhcp6__message_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dhcp6__option_8h" name="tnet_dhcp6_option.h" local="yes" imported="no">tnet_dhcp6_option.h</includes>
+ <class kind="struct">tnet_dhcp6_message_s</class>
+ <member kind="typedef">
+ <type>enum tnet_dhcp6_message_type_e</type>
+ <name>tnet_dhcp6_message_type_t</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a0bcb6998750e054507a274a9e472d9a1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_message_s</type>
+ <name>tnet_dhcp6_message_t</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a7760565583413b629d7a07a9e29b4127</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_dhcp6_messages_L_t</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a0d743e984418aa468d03b72d71ad8feb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_dhcp6_message_t</type>
+ <name>tnet_dhcp6_request_t</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>aa865622fe65b53de943c7a707bcae9bc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_dhcp6_message_t</type>
+ <name>tnet_dhcp6_reply_t</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a45b3436dedd8df1cc9dbcc5926250860</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dhcp6_message_type_e</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_solicit</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051fa752d897b810360fba91c3c8d8ec3312c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_advertise</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051fafd50f635f56e1c6430c7a7d3a4b07747</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_request</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051fa8c4f308655ddd23c677ed36652c76cce</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_confirm</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051fa269988c1d51a8ba5aaec3a166baa1eba</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_renew</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051fa951d6681cdfed91bb96b57b17e9aeff7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_rebind</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051fa969ca16f1829dd91323dc2fa5394736f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_reply</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051faeb4607fab695e013e71f0620586e3210</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_release</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051fa2d441ba472324c0bc30c2242491eac6d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_decline</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051faa761896a9e21e6973d0525e014198edf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_reconfigure</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051fa935a038fee6b2fee577300c88540bdbe</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_information_request</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051fa6ea39e333ea3009f149c5c5a5d0c9fc2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_relay_forw</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051fac719efc885894060c1c2981d88bcb43c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_type_relay_repl</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a08323bace5a61ab47ec9035230fd051facd0f656ce45fa652dbfe61b9e174eb68</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_dhcp6_message_serialize</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a765adabb5c24a3202851887aede7b2a6</anchor>
+ <arglist>(const struct tnet_dhcp6_ctx_s *ctx, const tnet_dhcp6_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_message_t *</type>
+ <name>tnet_dhcp6_message_deserialize</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a4ce79b2c9ad5e947922a0dc8bf1a4b86</anchor>
+ <arglist>(const struct tnet_dhcp6_ctx_s *ctx, const uint8_t *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_message_t *</type>
+ <name>tnet_dhcp6_message_create</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>ad4f84b23d7525a65b49b4cf0959cb2e7</anchor>
+ <arglist>(tnet_dhcp6_message_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_request_t *</type>
+ <name>tnet_dhcp6_request_create</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a86e344131239a1abbc0a5b2020ba570c</anchor>
+ <arglist>(tnet_dhcp6_message_type_t type)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_message_def_t</name>
+ <anchorfile>tnet__dhcp6__message_8h.html</anchorfile>
+ <anchor>a3a81bc718d8e4a5337b9323898674b65</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp6_option.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6/</path>
+ <filename>tnet__dhcp6__option_8c</filename>
+ <includes id="tnet__dhcp6__option_8h" name="tnet_dhcp6_option.h" local="yes" imported="no">tnet_dhcp6_option.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dhcp6_option_t *</type>
+ <name>tnet_dhcp6_option_create</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a85748a874ec0bffb44e93bc8736b5d3e</anchor>
+ <arglist>(tnet_dhcp6_option_code_t code, const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_option_identifier_t *</type>
+ <name>tnet_dhcp6_option_indentifer_create</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a40b898765178c4cd270f8e434a60e99c</anchor>
+ <arglist>(tnet_dhcp6_option_code_t code, const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_option_identifier_t *</type>
+ <name>tnet_dhcp6_option_clientid_create</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a9580a04b7683486bed424ddabde6363a</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_option_identifier_t *</type>
+ <name>tnet_dhcp6_option_serverid_create</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>ac09403b11d38fa71d5e43e8764b8b3d0</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_option_orequest_t *</type>
+ <name>tnet_dhcp6_option_orequest_create</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>aee59d1f340f3dcb41b5f2d26d3d4205f</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_option_orequest_t *</type>
+ <name>tnet_dhcp6_option_orequest_create_null</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>ab0c5c5a2ebd3c1c52d37baf37b325125</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_option_vendorclass_t *</type>
+ <name>tnet_dhcp6_option_vendorclass_create</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a5531acf377107cd2aa88ffd3870ba380</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_option_vendorclass_t *</type>
+ <name>tnet_dhcp6_option_vendorclass_create_null</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>ad966bc23c12478675fc8f67345bc2398</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_option_t *</type>
+ <name>tnet_dhcp6_option_deserialize</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a6deadd8ce3e250a9c2d0d5f9d2aa1417</anchor>
+ <arglist>(const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_option_serialize</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a616180ce101ac37af7279cd50f754176</anchor>
+ <arglist>(const tnet_dhcp6_option_t *self, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_option_serializeex</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a1365ca6c4618af8148b33da50e5014ce</anchor>
+ <arglist>(tnet_dhcp6_option_code_t code, uint8_t length, const void *value, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_option_orequest_add_code</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a78b0a34a3f71f481b62bef2e62a62ae2</anchor>
+ <arglist>(tnet_dhcp6_option_orequest_t *self, uint16_t code)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_option_def_t</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a4d539d4293a5ffe07892de7e47446c0e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_option_identifier_def_t</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>ac27e5694e1acf4290f84bb4a3d6f9922</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_option_orequest_def_t</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a1d68df186f478624ee10190391fec0ea</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_option_vendorclass_def_t</name>
+ <anchorfile>tnet__dhcp6__option_8c.html</anchorfile>
+ <anchor>a58062e3e28be055815c209a17e73d277</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dhcp6_option.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6/</path>
+ <filename>tnet__dhcp6__option_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dhcp6__duid_8h" name="tnet_dhcp6_duid.h" local="yes" imported="no">tnet_dhcp6_duid.h</includes>
+ <class kind="struct">tnet_dhcp6_option_data_s</class>
+ <class kind="struct">tnet_dhcp6_option_s</class>
+ <class kind="struct">tnet_dhcp6_option_identifier_s</class>
+ <class kind="struct">tnet_dhcp6_option_orequest_s</class>
+ <class kind="struct">tnet_dhcp6_option_vendorclass_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP6_OPTION</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>aee20957dcd988b9eeb518c7dd5b29b0c</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DECLARE_DHCP6_OPTION_DATA</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>af4e4efa6aafda6f9655e1f107ebcff64</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DECLARE_DHCP6_OPTION</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a1ed5fab473cbbdae0872f7b01f7b1901</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dhcp6_option_code_e</type>
+ <name>tnet_dhcp6_option_code_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a831211e647d27d29c4137a406e0aa754</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dhcp6_statuscode_e</type>
+ <name>tnet_dhcp6_statuscode_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a8a4ebada9e439ad886c5749e74d059dc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_option_data_s</type>
+ <name>tnet_dhcp6_option_data_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a80e20b0d831003308feb3f8b0521639a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_option_s</type>
+ <name>tnet_dhcp6_option_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>ae1d01310fe3e2833f086e881ce3f9def</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_dhcp6_options_L_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>adda8965a7c025d246c08c179c4025166</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_option_identifier_s</type>
+ <name>tnet_dhcp6_option_identifier_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>ae7b3e87849bdddd627541ac8b5cfa1d7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_dhcp6_option_identifier_t</type>
+ <name>tnet_dhcp6_option_clientid_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>aee3178ccfb9a0b673049f4e810ff8533</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_dhcp6_option_identifier_t</type>
+ <name>tnet_dhcp6_option_serverid_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>ad07c128ed8dfd9a9f478cada29af691a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_option_orequest_s</type>
+ <name>tnet_dhcp6_option_orequest_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a17908a94b442306f9ff55fbef7fc2007</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp6_option_vendorclass_s</type>
+ <name>tnet_dhcp6_option_vendorclass_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>acbc7975ffa9445566f76460082c17c63</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dhcp6_option_code_e</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_clientid</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755a3327501be0a9487e75ac42ce86a36e67</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_serverid</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755adca89895d7bbd1fe8e20c28398075ab3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_ia_na</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755ad64dd81543ed891886c102099798c36a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_ia_ta</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755adf0877126eb37e961e0fc9d6e404c224</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_iaaddr</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755add94edfa6121b8778986194871b47ab0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_oro</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755a45f7a09638657fb5acd4f3985d446551</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_preference</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755a61ffa98b9e00f00c48788b1501ff3ea2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_elapsed_time</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755ab4c8310c86603be2e86b3aedf5b5101a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_relay_msg</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755a5fd852298a96a6fe86e96dab116182c5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_auth</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755aca52feda034b487bfcc7b0d916ec52a9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_unicast</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755a27798813cf5efbd66b3ae6930798ebcc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_status_code</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755af21f3fecb13fccab021ddf3b6935b27f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_rapid_commit</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755ad1d6fa5166fa0c40fdcc30a8cb702340</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_user_class</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755a5d8ae4e5e4f262b7d11a913eaecd3c0c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_vendor_class</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755ac165ac987ca81ee5d869584fbcdadcf8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_vendor_opts</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755a9e056b5604dfe319deb2e8cd58861afa</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_interface_id</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755ad0304c4f94eb24f4c16c84253c003ec6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_reconf_msg</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755a7ed5183ce5d4957dcad4bba1e0fb0553</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_code_reconf_accept</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a18e26c5402e469dd0b563e74157755a7dd4ea51d8c318bce7fc7176e7372c2b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dhcp6_statuscode_e</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a1e604c89f4b34f7c0aa133c0d9ec3a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_statuscode_Success</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a1e604c89f4b34f7c0aa133c0d9ec3aa5fe1bbfa18c93352d763406a6abee895</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_statuscode_UnspecFail</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a1e604c89f4b34f7c0aa133c0d9ec3aa5211f6b0b6572ff6639fe19868d2a1a1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_statuscode_NoAddrsAvail</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a1e604c89f4b34f7c0aa133c0d9ec3aab7aaf46c2c61305b063f2d95c0cdced0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_statuscode_NoBinding</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a1e604c89f4b34f7c0aa133c0d9ec3aa82d74c3472d527e8fb7ee35d683c561c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_statuscode_NotOnLink</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a1e604c89f4b34f7c0aa133c0d9ec3aaf150cd0a65b9dcf8b149df553c9829a2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>dhcp6_statuscode_UseMulticast</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6a1e604c89f4b34f7c0aa133c0d9ec3aa5f0a83e8f0700574bd962c5e67ed0ba0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_option_t *</type>
+ <name>tnet_dhcp6_option_deserialize</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a6deadd8ce3e250a9c2d0d5f9d2aa1417</anchor>
+ <arglist>(const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_option_serialize</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a616180ce101ac37af7279cd50f754176</anchor>
+ <arglist>(const tnet_dhcp6_option_t *self, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp6_option_serializeex</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a1365ca6c4618af8148b33da50e5014ce</anchor>
+ <arglist>(tnet_dhcp6_option_code_t code, uint8_t length, const void *value, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dhcp6_option_orequest_add_code</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a254494dfc26351e8535871b753f8ef92</anchor>
+ <arglist>(tnet_dhcp6_option_orequest_t *self, uint16_t code)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_option_t *</type>
+ <name>tnet_dhcp6_option_create</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a9123e1057d08e16a258f31a7b946141d</anchor>
+ <arglist>(tnet_dhcp6_option_code_t code, const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_option_identifier_t *</type>
+ <name>tnet_dhcp6_option_indentifer_create</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>adfef6b59485ca292c871e7099990a983</anchor>
+ <arglist>(tnet_dhcp6_option_code_t code, const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_option_identifier_t *</type>
+ <name>tnet_dhcp6_option_clientid_create</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a41729803caa5cfed4cc32b628d12cea3</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_option_identifier_t *</type>
+ <name>tnet_dhcp6_option_serverid_create</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a32baebeda950dddbcb7b097fa802610b</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_option_orequest_t *</type>
+ <name>tnet_dhcp6_option_orequest_create</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>aa01c6f0e1dab917ad548e6b9ca24c5a3</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_option_orequest_t *</type>
+ <name>tnet_dhcp6_option_orequest_create_null</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a226b391dadb710d3ad724d2dd9e01ff4</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_option_vendorclass_t *</type>
+ <name>tnet_dhcp6_option_vendorclass_create</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>abc11e9ad6fde65adb466965e97519a49</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dhcp6_option_vendorclass_t *</type>
+ <name>tnet_dhcp6_option_vendorclass_create_null</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a194c3360bfcc440c40876408aa66f827</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_option_def_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>aca4bbdf87981922b053808636c8c7dfc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_option_identifier_def_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a01cef52de83efd6444c6b70f2ecb2e91</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_option_orequest_def_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a7b8899d2a304e8dd5295cb126123ebee</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dhcp6_option_vendorclass_def_t</name>
+ <anchorfile>tnet__dhcp6__option_8h.html</anchorfile>
+ <anchor>a8820aedacaef53f0e229fdc8fa0f37fb</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns_8c</filename>
+ <includes id="tnet__dns_8h" name="tnet_dns.h" local="yes" imported="no">tnet_dns.h</includes>
+ <includes id="tnet__dns__regexp_8h" name="tnet_dns_regexp.h" local="yes" imported="no">tnet_dns_regexp.h</includes>
+ <includes id="tnet__dns__message_8h" name="tnet_dns_message.h" local="yes" imported="no">tnet_dns_message.h</includes>
+ <includes id="tnet__dns__opt_8h" name="tnet_dns_opt.h" local="yes" imported="no">tnet_dns_opt.h</includes>
+ <includes id="tnet__dns__srv_8h" name="tnet_dns_srv.h" local="yes" imported="no">tnet_dns_srv.h</includes>
+ <includes id="tnet__dns__naptr_8h" name="tnet_dns_naptr.h" local="yes" imported="no">tnet_dns_naptr.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_cache_maintenance</name>
+ <anchorfile>tnet__dns_8c.html</anchorfile>
+ <anchor>a16c6661ccdbde58b205fa5c9366f0581</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_cache_entry_add</name>
+ <anchorfile>tnet__dns_8c.html</anchorfile>
+ <anchor>a9ec0ba4b1b141c296cba22236a4fa179</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t *response)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_dns_cache_entry_t *</type>
+ <name>tnet_dns_cache_entry_get</name>
+ <anchorfile>tnet__dns_8c.html</anchorfile>
+ <anchor>a510ba4e4ee2029a62b548239bed72e5e</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_ctx_t *</type>
+ <name>tnet_dns_ctx_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga080c974f8f6bdb3779bfae98956e9821</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_cache_entry_t *</type>
+ <name>tnet_dns_cache_entry_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga130888ddea8e08e520a2ffd02278d90d</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t *answer)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_cache_clear</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga4908f53f564e46f39472e1dc825aa3ce</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_response_t *</type>
+ <name>tnet_dns_resolve</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaaaee535d51058d67d9f170239de354b3</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_response_t *</type>
+ <name>tnet_dns_enum</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaf08d4dbbaf1025a17613bd553bf4db78</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *e164num, const char *domain)</arglist>
+ </member>
+ <member kind="function">
+ <type>char *</type>
+ <name>tnet_dns_enum_2</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga1aa07c721d9e2e7bac6eea9f44a515c8</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *service, const char *e164num, const char *domain)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_query_srv</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gab4b9b4f145decf0d2886c8a4ea25a313</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *service, char **hostname, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_query_naptr_srv</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga0c2c6cdb03f205b6ce16af9398d91730</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *domain, const char *service, char **hostname, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_add_server</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga9d617f0cf0f0dc70e4a3bca53ab23824</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *host)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_cache_entry_def_t</name>
+ <anchorfile>tnet__dns_8c.html</anchorfile>
+ <anchor>a3558b767074cab929ebb5ff83ea07e87</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_ctx_def_t</name>
+ <anchorfile>tnet__dns_8c.html</anchorfile>
+ <anchor>a9794de95cdab15b74749bba2f785f9d8</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__message_8h" name="tnet_dns_message.h" local="yes" imported="no">tnet_dns_message.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <class kind="struct">tnet_dns_cache_entry_s</class>
+ <class kind="struct">tnet_dns_ctx_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_CACHE_TTL</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gad0036c81833a0d67783075346183f741</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_TIMEOUT_DEFAULT</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga27019bac31c0cd87fcf5f1d440d44db2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_DGRAM_SIZE_DEFAULT</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga3f0a0842a1099131e50c4ce1358a8d66</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_SERVER_PORT_DEFAULT</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga3687b2e64d73b85594bd93a79df252af</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dns_cache_entry_s</type>
+ <name>tnet_dns_cache_entry_t</name>
+ <anchorfile>tnet__dns_8h.html</anchorfile>
+ <anchor>a0f0ec5cf80cda2b90ebbfb2ea91b8546</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_dns_cache_entries_L_t</name>
+ <anchorfile>tnet__dns_8h.html</anchorfile>
+ <anchor>ac5807116c43b05393fa66ca5137ea76e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_dns_cache_entries_L_t</type>
+ <name>tnet_dns_cache_t</name>
+ <anchorfile>tnet__dns_8h.html</anchorfile>
+ <anchor>a5a93db2cfefb5ba985653fa2b22d330c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dns_ctx_s</type>
+ <name>tnet_dns_ctx_t</name>
+ <anchorfile>tnet__dns_8h.html</anchorfile>
+ <anchor>a4eda9ed5b03bf8b4886156c1f103a4ea</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dns_cache_clear</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga4908f53f564e46f39472e1dc825aa3ce</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dns_response_t *</type>
+ <name>tnet_dns_resolve</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaaaee535d51058d67d9f170239de354b3</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dns_response_t *</type>
+ <name>tnet_dns_enum</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaf08d4dbbaf1025a17613bd553bf4db78</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *e164num, const char *domain)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API char *</type>
+ <name>tnet_dns_enum_2</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga1aa07c721d9e2e7bac6eea9f44a515c8</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *service, const char *e164num, const char *domain)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dns_query_srv</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gab4b9b4f145decf0d2886c8a4ea25a313</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *service, char **hostname, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dns_query_naptr_srv</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga0c2c6cdb03f205b6ce16af9398d91730</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *domain, const char *service, char **hostname, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dns_add_server</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga9d617f0cf0f0dc70e4a3bca53ab23824</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *host)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dns_ctx_t *</type>
+ <name>tnet_dns_ctx_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga080c974f8f6bdb3779bfae98956e9821</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_ctx_def_t</name>
+ <anchorfile>tnet__dns_8h.html</anchorfile>
+ <anchor>abbdfc081a1491c06e89261c44cd60d5f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_cache_entry_def_t</name>
+ <anchorfile>tnet__dns_8h.html</anchorfile>
+ <anchor>a4efb02fd4cb984ebac4138e560ee9905</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_a.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__a_8c</filename>
+ <includes id="tnet__dns__a_8h" name="tnet_dns_a.h" local="yes" imported="no">tnet_dns_a.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dns_a_t *</type>
+ <name>tnet_dns_a_create</name>
+ <anchorfile>tnet__dns__a_8c.html</anchorfile>
+ <anchor>a9defb7c8612dda2afe5c22a9d8af2cc2</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_a_def_t</name>
+ <anchorfile>tnet__dns__a_8c.html</anchorfile>
+ <anchor>ac8c60b42680e0c32a283b160f4a879ab</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_a.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__a_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_a_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_a_s</type>
+ <name>tnet_dns_a_t</name>
+ <anchorfile>tnet__dns__a_8h.html</anchorfile>
+ <anchor>ab141c5a0e9b9d0cf3409eb8360ec73f2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dns_a_t *</type>
+ <name>tnet_dns_a_create</name>
+ <anchorfile>tnet__dns__a_8h.html</anchorfile>
+ <anchor>a127c4a7530752dd17159d6cce2ec933d</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_a_def_t</name>
+ <anchorfile>tnet__dns__a_8h.html</anchorfile>
+ <anchor>aba9a5fca5fea194ada56d10229863ccf</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_aaaa.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__aaaa_8c</filename>
+ <includes id="tnet__dns__aaaa_8h" name="tnet_dns_aaaa.h" local="yes" imported="no">tnet_dns_aaaa.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dns_aaaa_t *</type>
+ <name>tnet_dns_aaaa_create</name>
+ <anchorfile>tnet__dns__aaaa_8c.html</anchorfile>
+ <anchor>a9af77e5771ba53c408d586b064292f57</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_aaaa_def_t</name>
+ <anchorfile>tnet__dns__aaaa_8c.html</anchorfile>
+ <anchor>acb37a50064cef53a2492b240ffeb0451</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_aaaa.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__aaaa_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_aaaa_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_aaaa_s</type>
+ <name>tnet_dns_aaaa_t</name>
+ <anchorfile>tnet__dns__aaaa_8h.html</anchorfile>
+ <anchor>af029948ea55fd7149a3690373f3fc8b2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_aaaa_t *</type>
+ <name>tnet_dns_aaaa_create</name>
+ <anchorfile>tnet__dns__aaaa_8h.html</anchorfile>
+ <anchor>a9af77e5771ba53c408d586b064292f57</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_aaaa_def_t</name>
+ <anchorfile>tnet__dns__aaaa_8h.html</anchorfile>
+ <anchor>a96c0dd56a4c355044d58f0d53ff4aee8</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_cname.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__cname_8c</filename>
+ <includes id="tnet__dns__cname_8h" name="tnet_dns_cname.h" local="yes" imported="no">tnet_dns_cname.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <member kind="function">
+ <type>tnet_dns_cname_t *</type>
+ <name>tnet_dns_cname_create</name>
+ <anchorfile>tnet__dns__cname_8c.html</anchorfile>
+ <anchor>a5dcf5f68f15132d89bafa3a061a62626</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_cname_def_t</name>
+ <anchorfile>tnet__dns__cname_8c.html</anchorfile>
+ <anchor>a8c03019ed6c906c4ec3bea95751654be</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_cname.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__cname_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_cname_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_cname_s</type>
+ <name>tnet_dns_cname_t</name>
+ <anchorfile>tnet__dns__cname_8h.html</anchorfile>
+ <anchor>a03c83c67bce0fe05e2417f0d4d94425c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_cname_t *</type>
+ <name>tnet_dns_cname_create</name>
+ <anchorfile>tnet__dns__cname_8h.html</anchorfile>
+ <anchor>a5dcf5f68f15132d89bafa3a061a62626</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_cname_def_t</name>
+ <anchorfile>tnet__dns__cname_8h.html</anchorfile>
+ <anchor>a7d6aea0757005c803e88b2fbb58b7ec6</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_message.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__message_8c</filename>
+ <includes id="tnet__dns__message_8h" name="tnet_dns_message.h" local="yes" imported="no">tnet_dns_message.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">../tnet_utils.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dns_message_t *</type>
+ <name>tnet_dns_message_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga98138daa781d9c12a4ba43f3371d0895</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tsk_bool_t isquery)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_message_t *</type>
+ <name>tnet_dns_message_create_null</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga353b8a830ee67c2a2d2a6e810f081ea9</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_response_t *</type>
+ <name>tnet_dns_response_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaca11f63942b2ed04516a0d2323c75e7f</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_query_t *</type>
+ <name>tnet_dns_query_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gac97c055c0a0a84882eb586feb22ef097</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_dns_message_serialize</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga98f52e21a3d361e2a837993c31756871</anchor>
+ <arglist>(const tnet_dns_message_t *message)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_message_t *</type>
+ <name>tnet_dns_message_deserialize</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga72d0a558aa990326e3724bd06260ac65</anchor>
+ <arglist>(const uint8_t *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_message_def_t</name>
+ <anchorfile>tnet__dns__message_8c.html</anchorfile>
+ <anchor>a7b52fae969a8d3fdbcaf82892ad14803</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_message.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__message_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_message_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_MESSAGE_IS_RESPONSE</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga2a5cf37ea80a5c81714042074eac92bf</anchor>
+ <arglist>(message)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_MESSAGE_IS_QUERY</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaf24bf109d5da866b600989d53c24f2aa</anchor>
+ <arglist>(message)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_RESPONSE_IS_SUCCESS</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaefa196185f91151ec1b70542d73f230b</anchor>
+ <arglist>(response)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_RESPONSE_IS_ERROR</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gab7b1d2b4373729da855fad1816ef9e81</anchor>
+ <arglist>(response)</arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dns_rcode_e</type>
+ <name>tnet_dns_rcode_t</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>a10a2d61b100eaa8fa40121a04227746e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dns_opcode_e</type>
+ <name>tnet_dns_opcode_t</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>ac70fc820dc3345398e3d71dec208a0ba</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dns_message_s</type>
+ <name>tnet_dns_message_t</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>adfe20e6afb683c719dfa690aa0ae82ca</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_dns_messages_L_t</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>a70167cb0e8bc6f7df28b176d58616b65</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_dns_message_t</type>
+ <name>tnet_dns_query_t</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>aa5e144b50fc52b3cd87fd9cfe230cb79</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_dns_message_t</type>
+ <name>tnet_dns_response_t</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>a5c96624b434eaa634b5dde4dee92ff61</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dns_rcode_e</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>a2d9be471d959638233c90adb121505fd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>rcode_noerror</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>a2d9be471d959638233c90adb121505fdafb49d1855d22e2a14b9164e83f21c4d8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>rcode_error_format</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>a2d9be471d959638233c90adb121505fda9eed8ffe73f0b6ac420350008aee371d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>rcode_server_failure</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>a2d9be471d959638233c90adb121505fda2a9b39e282a286f2200701c6a6f5e2e3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>rcode_error_name</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>a2d9be471d959638233c90adb121505fda0a69068bb631f39be6036eff8d973530</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>rcode_notimplemented</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>a2d9be471d959638233c90adb121505fda51b705ad2e1bc9a41fd7289e69fc0217</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>rcode_refused</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>a2d9be471d959638233c90adb121505fdaa19a2787f2f80124a9d8a26bdcec5f0f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dns_opcode_e</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>ae948f57e10a3e473e1f37d13d7e571da</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>opcode_query</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>ae948f57e10a3e473e1f37d13d7e571daaf16852803537cc6a78d86024593654ae</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>opcode_iquery</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>ae948f57e10a3e473e1f37d13d7e571daa1d4afedc5e0d6721a623d5420110d53a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>opcode_status</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>ae948f57e10a3e473e1f37d13d7e571daab0ef3fad224dc5971f97e02b2fb8b714</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_dns_message_serialize</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga98f52e21a3d361e2a837993c31756871</anchor>
+ <arglist>(const tnet_dns_message_t *message)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_message_t *</type>
+ <name>tnet_dns_message_deserialize</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga72d0a558aa990326e3724bd06260ac65</anchor>
+ <arglist>(const uint8_t *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_message_t *</type>
+ <name>tnet_dns_message_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga98138daa781d9c12a4ba43f3371d0895</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tsk_bool_t isquery)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_message_t *</type>
+ <name>tnet_dns_message_create_null</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga353b8a830ee67c2a2d2a6e810f081ea9</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_response_t *</type>
+ <name>tnet_dns_response_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaca11f63942b2ed04516a0d2323c75e7f</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_query_t *</type>
+ <name>tnet_dns_query_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gac97c055c0a0a84882eb586feb22ef097</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_message_def_t</name>
+ <anchorfile>tnet__dns__message_8h.html</anchorfile>
+ <anchor>afa9682338ba81c46be181f6e7a63d53d</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_mx.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__mx_8c</filename>
+ <includes id="tnet__dns__mx_8h" name="tnet_dns_mx.h" local="yes" imported="no">tnet_dns_mx.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dns_mx_t *</type>
+ <name>tnet_dns_mx_create</name>
+ <anchorfile>tnet__dns__mx_8c.html</anchorfile>
+ <anchor>a016b5719ecb6b707228b4350281ecee2</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_mx_def_t</name>
+ <anchorfile>tnet__dns__mx_8c.html</anchorfile>
+ <anchor>a005d5f47204c5bb134f6b0fa5b1a1ced</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_mx.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__mx_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_mx_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_mx_s</type>
+ <name>tnet_dns_mx_t</name>
+ <anchorfile>tnet__dns__mx_8h.html</anchorfile>
+ <anchor>a612a857249dd90d7bb72d186b534fd7f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_mx_t *</type>
+ <name>tnet_dns_mx_create</name>
+ <anchorfile>tnet__dns__mx_8h.html</anchorfile>
+ <anchor>a016b5719ecb6b707228b4350281ecee2</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_mx_def_t</name>
+ <anchorfile>tnet__dns__mx_8h.html</anchorfile>
+ <anchor>aa421813d4ec3a8eed3f247fef75ddfe9</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_naptr.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__naptr_8c</filename>
+ <includes id="tnet__dns__naptr_8h" name="tnet_dns_naptr.h" local="yes" imported="no">tnet_dns_naptr.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">./tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dns_naptr_t *</type>
+ <name>tnet_dns_naptr_create</name>
+ <anchorfile>tnet__dns__naptr_8c.html</anchorfile>
+ <anchor>a8903290f814d88d1b685e3401591e8c3</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_naptr_def_t</name>
+ <anchorfile>tnet__dns__naptr_8c.html</anchorfile>
+ <anchor>aad6c6ba633c90e84931baa0af523a42d</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_naptr.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__naptr_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_naptr_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_naptr_s</type>
+ <name>tnet_dns_naptr_t</name>
+ <anchorfile>tnet__dns__naptr_8h.html</anchorfile>
+ <anchor>a40135eba84ad5108ead55d1198e9df63</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dns_naptr_t *</type>
+ <name>tnet_dns_naptr_create</name>
+ <anchorfile>tnet__dns__naptr_8h.html</anchorfile>
+ <anchor>aa59f7ef27b64bf1340e75bfa3b8ded0d</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_naptr_def_t</name>
+ <anchorfile>tnet__dns__naptr_8h.html</anchorfile>
+ <anchor>a0f60311c1ef28f1999ecba475352922f</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_ns.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__ns_8c</filename>
+ <includes id="tnet__dns__ns_8h" name="tnet_dns_ns.h" local="yes" imported="no">tnet_dns_ns.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <member kind="function">
+ <type>tnet_dns_ns_t *</type>
+ <name>tnet_dns_ns_create</name>
+ <anchorfile>tnet__dns__ns_8c.html</anchorfile>
+ <anchor>a1f6a6ec6af069ac55d709f6313ea0f89</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_ns_def_t</name>
+ <anchorfile>tnet__dns__ns_8c.html</anchorfile>
+ <anchor>a30c52ab96205e922203a9cb983b1814c</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_ns.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__ns_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_ns_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_ns_s</type>
+ <name>tnet_dns_ns_t</name>
+ <anchorfile>tnet__dns__ns_8h.html</anchorfile>
+ <anchor>a20afc97fb196ce2a3b1a4eb94603891f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dns_ns_t *</type>
+ <name>tnet_dns_ns_create</name>
+ <anchorfile>tnet__dns__ns_8h.html</anchorfile>
+ <anchor>a32c62e90da38fed47351cd1ecdfe7323</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_ns_def_t</name>
+ <anchorfile>tnet__dns__ns_8h.html</anchorfile>
+ <anchor>a848fe1ef765215af38d449d4b0fd5943</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_opt.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__opt_8c</filename>
+ <includes id="tnet__dns__opt_8h" name="tnet_dns_opt.h" local="yes" imported="no">tnet_dns_opt.h</includes>
+ <member kind="function">
+ <type>tnet_dns_opt_t *</type>
+ <name>tnet_dns_opt_create</name>
+ <anchorfile>tnet__dns__opt_8c.html</anchorfile>
+ <anchor>a42d82b4cfecece6f35d08124861cd624</anchor>
+ <arglist>(tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_opt_def_t</name>
+ <anchorfile>tnet__dns__opt_8c.html</anchorfile>
+ <anchor>ac54263af0e117f7ddd77eeb5bb77add3</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_opt.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__opt_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_opt_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_opt_s</type>
+ <name>tnet_dns_opt_t</name>
+ <anchorfile>tnet__dns__opt_8h.html</anchorfile>
+ <anchor>aad1e4934eb5b8f462bf2fd70d3557d0b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_opt_t *</type>
+ <name>tnet_dns_opt_create</name>
+ <anchorfile>tnet__dns__opt_8h.html</anchorfile>
+ <anchor>a42d82b4cfecece6f35d08124861cd624</anchor>
+ <arglist>(tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_opt_def_t</name>
+ <anchorfile>tnet__dns__opt_8h.html</anchorfile>
+ <anchor>a87bc155048ab772c6e275779c7a903fe</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_ptr.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__ptr_8c</filename>
+ <includes id="tnet__dns__ptr_8h" name="tnet_dns_ptr.h" local="yes" imported="no">tnet_dns_ptr.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <member kind="function">
+ <type>tnet_dns_ptr_t *</type>
+ <name>tnet_dns_ptr_create</name>
+ <anchorfile>tnet__dns__ptr_8c.html</anchorfile>
+ <anchor>a0781972d80ae72b2836b931106dc922b</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_ptr_def_t</name>
+ <anchorfile>tnet__dns__ptr_8c.html</anchorfile>
+ <anchor>a322649cfc864a32b9a169f89a4d88ece</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_ptr.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__ptr_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_ptr_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_ptr_s</type>
+ <name>tnet_dns_ptr_t</name>
+ <anchorfile>tnet__dns__ptr_8h.html</anchorfile>
+ <anchor>a36877f2a0e53fa1227a87f776d5ed6c5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_ptr_t *</type>
+ <name>tnet_dns_ptr_create</name>
+ <anchorfile>tnet__dns__ptr_8h.html</anchorfile>
+ <anchor>a0781972d80ae72b2836b931106dc922b</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_ptr_def_t</name>
+ <anchorfile>tnet__dns__ptr_8h.html</anchorfile>
+ <anchor>a7645989139aeb9e6c24c0c8995536ed5</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_regexp.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__regexp_8c</filename>
+ <includes id="tnet__dns__regexp_8h" name="tnet_dns_regexp.h" local="yes" imported="no">tnet_dns_regexp.h</includes>
+ <member kind="function">
+ <type>char *</type>
+ <name>tnet_dns_regex_parse</name>
+ <anchorfile>tnet__dns__regexp_8c.html</anchorfile>
+ <anchor>a9ed1816bfa7833863cf0743db5f26830</anchor>
+ <arglist>(const char *e164num, const char *regexp)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_regexp.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__regexp_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <member kind="function">
+ <type>TNET_BEGIN_DECLS TINYNET_API char *</type>
+ <name>tnet_dns_regex_parse</name>
+ <anchorfile>tnet__dns__regexp_8h.html</anchorfile>
+ <anchor>ad9b4290eea6c5833a15079a9ba6315b5</anchor>
+ <arglist>(const char *e164num, const char *regexp)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_resolvconf.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__resolvconf_8c</filename>
+ <includes id="tnet__dns__resolvconf_8h" name="tnet_dns_resolvconf.h" local="yes" imported="no">tnet_dns_resolvconf.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <includes id="tnet__dns_8h" name="tnet_dns.h" local="yes" imported="no">dns/tnet_dns.h</includes>
+ <member kind="function">
+ <type>tnet_addresses_L_t *</type>
+ <name>tnet_dns_resolvconf_parse</name>
+ <anchorfile>tnet__dns__resolvconf_8c.html</anchorfile>
+ <anchor>a450c767da8f966731be469a146759494</anchor>
+ <arglist>(const char *path)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_resolvconf.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__resolvconf_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <member kind="function">
+ <type>TNET_BEGIN_DECLS TINYNET_API tnet_addresses_L_t *</type>
+ <name>tnet_dns_resolvconf_parse</name>
+ <anchorfile>tnet__dns__resolvconf_8h.html</anchorfile>
+ <anchor>a7c7f9edfb32f7b57b9332973d1b7b217</anchor>
+ <arglist>(const char *path)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_rr.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__rr_8c</filename>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <includes id="tnet__dns__a_8h" name="tnet_dns_a.h" local="yes" imported="no">tnet_dns_a.h</includes>
+ <includes id="tnet__dns__aaaa_8h" name="tnet_dns_aaaa.h" local="yes" imported="no">tnet_dns_aaaa.h</includes>
+ <includes id="tnet__dns__cname_8h" name="tnet_dns_cname.h" local="yes" imported="no">tnet_dns_cname.h</includes>
+ <includes id="tnet__dns__mx_8h" name="tnet_dns_mx.h" local="yes" imported="no">tnet_dns_mx.h</includes>
+ <includes id="tnet__dns__naptr_8h" name="tnet_dns_naptr.h" local="yes" imported="no">tnet_dns_naptr.h</includes>
+ <includes id="tnet__dns__ns_8h" name="tnet_dns_ns.h" local="yes" imported="no">tnet_dns_ns.h</includes>
+ <includes id="tnet__dns__opt_8h" name="tnet_dns_opt.h" local="yes" imported="no">tnet_dns_opt.h</includes>
+ <includes id="tnet__dns__ptr_8h" name="tnet_dns_ptr.h" local="yes" imported="no">tnet_dns_ptr.h</includes>
+ <includes id="tnet__dns__soa_8h" name="tnet_dns_soa.h" local="yes" imported="no">tnet_dns_soa.h</includes>
+ <includes id="tnet__dns__srv_8h" name="tnet_dns_srv.h" local="yes" imported="no">tnet_dns_srv.h</includes>
+ <includes id="tnet__dns__txt_8h" name="tnet_dns_txt.h" local="yes" imported="no">tnet_dns_txt.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dns_rr_t *</type>
+ <name>tnet_dns_rr_create</name>
+ <anchorfile>tnet__dns__rr_8c.html</anchorfile>
+ <anchor>ac2a4807ec467a0c0d68a72cdcf2809c5</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_init</name>
+ <anchorfile>tnet__dns__rr_8c.html</anchorfile>
+ <anchor>abbf82aaca6c13787652a732688b951f0</anchor>
+ <arglist>(tnet_dns_rr_t *rr, tnet_dns_qtype_t qtype, tnet_dns_qclass_t qclass)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_deinit</name>
+ <anchorfile>tnet__dns__rr_8c.html</anchorfile>
+ <anchor>a96fbca3132c00d7f47d17a20eaf3384b</anchor>
+ <arglist>(tnet_dns_rr_t *rr)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_charstring_deserialize</name>
+ <anchorfile>tnet__dns__rr_8c.html</anchorfile>
+ <anchor>a120e1c355fecace1874329b58d700d4d</anchor>
+ <arglist>(const void *data, char **charstring, tsk_size_t *offset)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_qname_deserialize</name>
+ <anchorfile>tnet__dns__rr_8c.html</anchorfile>
+ <anchor>a1ade7e249886b86b6fb68dd6ee807d60</anchor>
+ <arglist>(const void *data, char **name, tsk_size_t *offset)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_qname_serialize</name>
+ <anchorfile>tnet__dns__rr_8c.html</anchorfile>
+ <anchor>aacf6eb1f4fc48c1b662c704ea0e6bb5a</anchor>
+ <arglist>(const char *qname, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_rr_t *</type>
+ <name>tnet_dns_rr_deserialize</name>
+ <anchorfile>tnet__dns__rr_8c.html</anchorfile>
+ <anchor>a6132fbb1895bc96764e773a0cbe8137f</anchor>
+ <arglist>(const void *data, tsk_size_t size, tsk_size_t *offset)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_serialize</name>
+ <anchorfile>tnet__dns__rr_8c.html</anchorfile>
+ <anchor>ad79d614d7a6e9cf9d9f69b381874cca1</anchor>
+ <arglist>(const tnet_dns_rr_t *rr, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_rr_def_t</name>
+ <anchorfile>tnet__dns__rr_8c.html</anchorfile>
+ <anchor>a1c8c9b8399afa3a95932cea38da3b855</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_rr.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__rr_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <class kind="struct">tnet_dns_rr_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_RR</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>aa1292467e3d3978fd7ac6c7b10f87cc2</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a5cccd210b99ecceb030738248f17b76a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dns_qtype_e</type>
+ <name>tnet_dns_qtype_t</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a62961afef3b1d8a3ce06b52a8a73db1d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dns_qclass_e</type>
+ <name>tnet_dns_qclass_t</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a69f1e6e11e7ef63d49fd0911e5ac3357</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dns_rr_s</type>
+ <name>tnet_dns_rr_t</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>ace26a1f5215afe27b8d0a16460ef1beb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_dns_rrs_L_t</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a92294f9508f61a03b7b5191acfa35f20</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dns_qtype_e</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6ae</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_a</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea6b82b9692226f36f5553fd6d9780f9d5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_ns</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea2c626ab43259347ad612a7230b478e9d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_md</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea99c0993087c8dbbc55e4b6afdc4e4c8b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_mf</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea36ce8cf8155642e552675d2fc25eae44</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_cname</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea45425b4d0e6bd387ecb36c90ae99d370</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_soa</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aeab40d6242e1e9586362fbd35086b64006</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_mb</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aeaa11cd279e87a961352188184c2f2d8d2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_mg</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aeaae9f1f64f391b7b455272f6cbde3ef8b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_mr</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aeab75b84867779598974a29609294ca0bb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_null</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea86f36a2d858188aed1c34b67fe62ffd6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_wks</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea4059a57c201d0101a37c4d3f9eabf31a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_ptr</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aeaed5edacf992f416dadc864f78c133459</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_hinfo</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea57b532f99f7b8333d46d1852336850d6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_minfo</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aeabea007dc92b66ce9be0d1c1d269e78f2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_mx</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea54ce802cf2003da33264c8e03812dfc9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_txt</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aeabc2ed8cc5ac7785b1494fc4d2cea915b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_aaaa</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea9352d81362b3407179adef085bdbce97</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_srv</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea00a47d3105646a15138910bbb4a2ea94</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_naptr</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea05b83408990091d7a963bfa4ed6651f5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_opt</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea8d2334865c3df5ee1ba23b9ca3a112d1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_ipseckey</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea252b893a0977eb9e3bd102654a71d825</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_spf</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aeac027ceb8ae33fe01d79b9b9e09f869cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qtype_any</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6d7667bb60a37e3cac21f13a0d2af6aea1a5b9dd4a833ad763b9bafc88a5cea5c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dns_qclass_e</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a39c6ee8ca1d8f814024a17cfc3a88b5c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qclass_in</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a39c6ee8ca1d8f814024a17cfc3a88b5caa8fb176df6c5bdca6b7f088a84fd0384</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qclass_ics</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a39c6ee8ca1d8f814024a17cfc3a88b5ca3fa1f9f5dd15959e92668ddcec709850</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qclass_ch</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a39c6ee8ca1d8f814024a17cfc3a88b5ca8503dc4ab6ee9b2293740abb26631d4a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qclass_hs</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a39c6ee8ca1d8f814024a17cfc3a88b5cab00871fa3fb8dccd9c3b5e4eed53bbe2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>qclass_any</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a39c6ee8ca1d8f814024a17cfc3a88b5cac9a4560ad311dfe6ee260f6578f35e73</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_init</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>abbf82aaca6c13787652a732688b951f0</anchor>
+ <arglist>(tnet_dns_rr_t *rr, tnet_dns_qtype_t qtype, tnet_dns_qclass_t qclass)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_deinit</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a96fbca3132c00d7f47d17a20eaf3384b</anchor>
+ <arglist>(tnet_dns_rr_t *rr)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_charstring_deserialize</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6ec4f0742d53673299905dbcf2285af0</anchor>
+ <arglist>(const void *data, char **name, tsk_size_t *offset)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_qname_deserialize</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a1ade7e249886b86b6fb68dd6ee807d60</anchor>
+ <arglist>(const void *data, char **name, tsk_size_t *offset)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_qname_serialize</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>aacf6eb1f4fc48c1b662c704ea0e6bb5a</anchor>
+ <arglist>(const char *qname, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_rr_t *</type>
+ <name>tnet_dns_rr_deserialize</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a6132fbb1895bc96764e773a0cbe8137f</anchor>
+ <arglist>(const void *data, tsk_size_t size, tsk_size_t *offset)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_rr_serialize</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>ad79d614d7a6e9cf9d9f69b381874cca1</anchor>
+ <arglist>(const tnet_dns_rr_t *rr, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_rr_def_t</name>
+ <anchorfile>tnet__dns__rr_8h.html</anchorfile>
+ <anchor>a15a335d6e37b391bfdfe754266ff7ee2</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_soa.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__soa_8c</filename>
+ <includes id="tnet__dns__soa_8h" name="tnet_dns_soa.h" local="yes" imported="no">tnet_dns_soa.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dns_soa_t *</type>
+ <name>tnet_dns_soa_create</name>
+ <anchorfile>tnet__dns__soa_8c.html</anchorfile>
+ <anchor>a554c9fb10b89674333c4358d9b22971f</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_soa_def_t</name>
+ <anchorfile>tnet__dns__soa_8c.html</anchorfile>
+ <anchor>a26a935ec9f0f1ee97cebff4c2bcd1d30</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_soa.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__soa_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_soa_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_soa_s</type>
+ <name>tnet_dns_soa_t</name>
+ <anchorfile>tnet__dns__soa_8h.html</anchorfile>
+ <anchor>a47c38512228462f2a7a2af3fdbbe5ee0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_soa_t *</type>
+ <name>tnet_dns_soa_create</name>
+ <anchorfile>tnet__dns__soa_8h.html</anchorfile>
+ <anchor>a554c9fb10b89674333c4358d9b22971f</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_soa_def_t</name>
+ <anchorfile>tnet__dns__soa_8h.html</anchorfile>
+ <anchor>a3ee61ed56ac01b434cb2ee7cbe7a3e47</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_srv.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__srv_8c</filename>
+ <includes id="tnet__dns__srv_8h" name="tnet_dns_srv.h" local="yes" imported="no">tnet_dns_srv.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_dns_srv_t *</type>
+ <name>tnet_dns_srv_create</name>
+ <anchorfile>tnet__dns__srv_8c.html</anchorfile>
+ <anchor>a0989e7656444afa8eccb494162c1a840</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_srv_def_t</name>
+ <anchorfile>tnet__dns__srv_8c.html</anchorfile>
+ <anchor>a446d9cf2ccb2fb1d5f3534c9bdabf047</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_srv.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__srv_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_srv_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_srv_s</type>
+ <name>tnet_dns_srv_t</name>
+ <anchorfile>tnet__dns__srv_8h.html</anchorfile>
+ <anchor>a4ebe2b222b25e6f185628a01bd80088f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_srv_t *</type>
+ <name>tnet_dns_srv_create</name>
+ <anchorfile>tnet__dns__srv_8h.html</anchorfile>
+ <anchor>a0989e7656444afa8eccb494162c1a840</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_srv_def_t</name>
+ <anchorfile>tnet__dns__srv_8h.html</anchorfile>
+ <anchor>a9ba8975bee55d2728c8902f752f5a064</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_txt.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__txt_8c</filename>
+ <includes id="tnet__dns__txt_8h" name="tnet_dns_txt.h" local="yes" imported="no">tnet_dns_txt.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <member kind="function">
+ <type>tnet_dns_txt_t *</type>
+ <name>tnet_dns_txt_create</name>
+ <anchorfile>tnet__dns__txt_8c.html</anchorfile>
+ <anchor>aae4a21dd9f1ea22c7f2f171dc63d501b</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dns_txt_def_t</name>
+ <anchorfile>tnet__dns__txt_8c.html</anchorfile>
+ <anchor>ae11da0ea12bd1bd4de45bace4264cf81</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dns_txt.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>tnet__dns__txt_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__dns__rr_8h" name="tnet_dns_rr.h" local="yes" imported="no">tnet_dns_rr.h</includes>
+ <class kind="struct">tnet_dns_txt_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_dns_txt_s</type>
+ <name>tnet_dns_txt_t</name>
+ <anchorfile>tnet__dns__txt_8h.html</anchorfile>
+ <anchor>ab03bd98bda63e6584c344f0fb68dd50a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_txt_t *</type>
+ <name>tnet_dns_txt_create</name>
+ <anchorfile>tnet__dns__txt_8h.html</anchorfile>
+ <anchor>aae4a21dd9f1ea22c7f2f171dc63d501b</anchor>
+ <arglist>(const char *name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void *data, tsk_size_t offset)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dns_txt_def_t</name>
+ <anchorfile>tnet__dns__txt_8h.html</anchorfile>
+ <anchor>a7e04769891a173ae81dded18394e3992</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice_8c</filename>
+ <includes id="tnet__ice_8h" name="tnet_ice.h" local="yes" imported="no">tnet_ice.h</includes>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">../tinynet_config.h</includes>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice_candidate.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice__candidate_8c</filename>
+ <includes id="tnet__ice__candidate_8h" name="tnet_ice_candidate.h" local="yes" imported="no">tnet_ice_candidate.h</includes>
+ <includes id="tnet__ice__utils_8h" name="tnet_ice_utils.h" local="yes" imported="no">tnet_ice_utils.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <member kind="define">
+ <type>#define</type>
+ <name>TRANSPORT_GET</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>ac0c81284ba3210ccad9e97f32a6d361a</anchor>
+ <arglist>(STR)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TRANSPORT_GET</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>a2a343a55abad1a887708009d2249c052</anchor>
+ <arglist>(STR, str)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_ice_candidate_t *</type>
+ <name>tnet_ice_candidate_create</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>a87afdc02b700ac02deef8f9db2e3b7d0</anchor>
+ <arglist>(tnet_ice_cand_type_t type_e, tnet_socket_t *socket, tsk_bool_t is_ice_jingle, tsk_bool_t is_rtp, tsk_bool_t is_video, const char *ufrag, const char *pwd, const char *foundation)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_ice_candidate_t *</type>
+ <name>tnet_ice_candidate_parse</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>adcafd3c75b3a0567af1c2923bbd479e9</anchor>
+ <arglist>(const char *str)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_candidate_set_credential</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>a88081be58407f8a55fed19635683d17c</anchor>
+ <arglist>(tnet_ice_candidate_t *self, const char *ufrag, const char *pwd)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_candidate_set_rflx_addr</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>abfc9b2e65927ce5f84dd58f168dc93ba</anchor>
+ <arglist>(tnet_ice_candidate_t *self, const char *addr, tnet_port_t port)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_ice_candidate_get_att_value</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>aec0c1278bea426308f7820a1a982bbb4</anchor>
+ <arglist>(const tnet_ice_candidate_t *self, const char *att_name)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_candidate_set_local_pref</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>ab2dbca1a8eb4356de3b660c9beb72540</anchor>
+ <arglist>(tnet_ice_candidate_t *self, uint16_t local_pref)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_ice_candidate_tostring</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>ab93d6f47bf868773438e47f47e077d13</anchor>
+ <arglist>(tnet_ice_candidate_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_candidate_send_stun_bind_request</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>a5b8c31b3a03f88f22e610c77d1482da9</anchor>
+ <arglist>(tnet_ice_candidate_t *self, struct sockaddr_storage *server_addr, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_candidate_process_stun_response</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>a5b4466b24e0e536e9ac6413c23c0c6b2</anchor>
+ <arglist>(tnet_ice_candidate_t *self, const tnet_stun_response_t *response, tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_ice_candidate_t *</type>
+ <name>tnet_ice_candidate_find_by_fd</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>ad8cc71f1264c8dcc74cc690c468c1bbe</anchor>
+ <arglist>(tnet_ice_candidates_L_t *candidates, tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_ice_candidate_get_ufrag</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>aa9bafda787d4b69a36fe1aa20c8af4d4</anchor>
+ <arglist>(const tnet_ice_candidate_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_ice_candidate_get_pwd</name>
+ <anchorfile>tnet__ice__candidate_8c.html</anchorfile>
+ <anchor>a0edc7f4dee8171abbb1e6fc678bc82f8</anchor>
+ <arglist>(const tnet_ice_candidate_t *self)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice_candidate.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice__candidate_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__stun__message_8h" name="tnet_stun_message.h" local="yes" imported="no">stun/tnet_stun_message.h</includes>
+ <includes id="tnet__socket_8h" name="tnet_socket.h" local="yes" imported="no">tnet_socket.h</includes>
+ <class kind="struct">tnet_ice_candidate_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_TRANSPORT_UDP</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ae1b662d5e6b0d21c09fd3f838b786f9a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_TRANSPORT_TCP</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a41130d885b4b5aa83a5f38c67eb9c9fb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_TRANSPORT_TLS</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>abc5d9b200c226b93a2daae472636fa8f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_TRANSPORT_SCTP</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a377a94ab79d2f01490b544755f0ed41b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_TRANSPORT_WS</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>af5d81604b62ec33d25e36a67c1251b4d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_TRANSPORT_WSS</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>aefca7739c4338f6fd3862d7dbf3bd637</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_TYPE_HOST</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a0006a60bf22085ddc6c3d8678a1fff7b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_TYPE_SRFLX</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>afd3cbe41244f7e2269eebdf3eb634b95</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_TYPE_PRFLX</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>aacd9ce8fb4b3bc07a4f03dbe6a36a945</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_TYPE_RELAY</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a52affc7b42846807f024604827377f41</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_PREF_HOST</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>af2364751ec9aa5d325db99afd8c10818</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_PREF_SRFLX</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a222b836f5b110bfe3f37ceab60d618db</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_PREF_PRFLX</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>afb9ae2f89f8226dde22048fb5fb8354a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_PREF_RELAY</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a7ac1c6c32135a99d1ca552c3bd58c1c2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_FOUNDATION_HOST</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a4145345d2588a18b53cae5c2f2cfa27f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_FOUNDATION_SRFLX</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ab506ffe464a7b1a294850cd06a3a00df</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_FOUNDATION_PRFLX</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a430eedeb2ce8ffa4d9c4c30d01dd85b3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_FOUNDATION_RELAY</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a585f8eab3dc73fd575467af9d930fce0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_COMPID_RTP</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a7d6a3ad5bb6bb0cfaa4e46a4c7882f6c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_COMPID_RTCP</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a13ac3d2da0fd98a4409861a222fceb40</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CANDIDATE_FOUND_SIZE_PREF</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a49640bfaea947b298170919d5e49cbba</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_ice_cand_type_e</type>
+ <name>tnet_ice_cand_type_t</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a6241699c76dc566092b4d7d5c29acc4f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_ice_candidate_s</type>
+ <name>tnet_ice_candidate_t</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a3d658380df87bf28a24603119b2870cb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_ice_candidates_L_t</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ad107252b8f7eb93e7561e7b664dffbaa</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_ice_cand_type_e</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ad04e165e02bc0661c9c16230e92f0cb8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_cand_type_unknown</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ad04e165e02bc0661c9c16230e92f0cb8a76e2e17a49bd0bf350e301e80e126422</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_cand_type_host</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ad04e165e02bc0661c9c16230e92f0cb8af95692833ce82ab03827bbb5e252807b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_cand_type_srflx</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ad04e165e02bc0661c9c16230e92f0cb8a49074a8972e6db8227397ec318cb8b7e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_cand_type_prflx</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ad04e165e02bc0661c9c16230e92f0cb8a05b142a102f38682b7edc9a2d1e6170d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_cand_type_relay</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ad04e165e02bc0661c9c16230e92f0cb8a3d21db646212621771c99c69eccd9458</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_ice_candidate_t *</type>
+ <name>tnet_ice_candidate_create</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a50b8cad64e556dd901cee0b443192502</anchor>
+ <arglist>(tnet_ice_cand_type_t type_e, struct tnet_socket_s *socket, tsk_bool_t is_ice_jingle, tsk_bool_t is_rtp, tsk_bool_t is_video, const char *ufrag, const char *pwd, const char *foundation)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_ice_candidate_t *</type>
+ <name>tnet_ice_candidate_parse</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a3c7cfe0e32560ddb9c95fff93102218f</anchor>
+ <arglist>(const char *str)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_candidate_set_credential</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a88081be58407f8a55fed19635683d17c</anchor>
+ <arglist>(tnet_ice_candidate_t *self, const char *ufrag, const char *pwd)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_candidate_set_rflx_addr</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>abfc9b2e65927ce5f84dd58f168dc93ba</anchor>
+ <arglist>(tnet_ice_candidate_t *self, const char *addr, tnet_port_t port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API const char *</type>
+ <name>tnet_ice_candidate_get_att_value</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a521930480b15845f6c971415c077f41d</anchor>
+ <arglist>(const tnet_ice_candidate_t *self, const char *att_name)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_candidate_set_local_pref</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ab2dbca1a8eb4356de3b660c9beb72540</anchor>
+ <arglist>(tnet_ice_candidate_t *self, uint16_t local_pref)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API const char *</type>
+ <name>tnet_ice_candidate_tostring</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a74f2f386a6a36578192cc54788bc3027</anchor>
+ <arglist>(tnet_ice_candidate_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_candidate_send_stun_bind_request</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a5b8c31b3a03f88f22e610c77d1482da9</anchor>
+ <arglist>(tnet_ice_candidate_t *self, struct sockaddr_storage *server_addr, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_candidate_process_stun_response</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a5b4466b24e0e536e9ac6413c23c0c6b2</anchor>
+ <arglist>(tnet_ice_candidate_t *self, const tnet_stun_response_t *response, tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_ice_candidate_t *</type>
+ <name>tnet_ice_candidate_find_by_fd</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>ad8cc71f1264c8dcc74cc690c468c1bbe</anchor>
+ <arglist>(tnet_ice_candidates_L_t *candidates, tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_ice_candidate_get_ufrag</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>aa9bafda787d4b69a36fe1aa20c8af4d4</anchor>
+ <arglist>(const tnet_ice_candidate_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_ice_candidate_get_pwd</name>
+ <anchorfile>tnet__ice__candidate_8h.html</anchorfile>
+ <anchor>a0edc7f4dee8171abbb1e6fc678bc82f8</anchor>
+ <arglist>(const tnet_ice_candidate_t *self)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice_ctx.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice__ctx_8c</filename>
+ <includes id="tnet__ice__ctx_8h" name="tnet_ice_ctx.h" local="yes" imported="no">tnet_ice_ctx.h</includes>
+ <includes id="tnet__ice__event_8h" name="tnet_ice_event.h" local="yes" imported="no">tnet_ice_event.h</includes>
+ <includes id="tnet__ice__candidate_8h" name="tnet_ice_candidate.h" local="yes" imported="no">tnet_ice_candidate.h</includes>
+ <includes id="tnet__ice__pair_8h" name="tnet_ice_pair.h" local="yes" imported="no">tnet_ice_pair.h</includes>
+ <includes id="tnet__ice__utils_8h" name="tnet_ice_utils.h" local="yes" imported="no">tnet_ice_utils.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">tnet_endianness.h</includes>
+ <includes id="tnet__stun_8h" name="tnet_stun.h" local="yes" imported="no">stun/tnet_stun.h</includes>
+ <includes id="tnet__stun__message_8h" name="tnet_stun_message.h" local="yes" imported="no">stun/tnet_stun_message.h</includes>
+ <class kind="struct">tnet_ice_ctx_s</class>
+ <class kind="struct">tnet_ice_action_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>LONG_MAX</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a50fece4db74f09568b2938db583c5655</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_DEBUG_STATE_MACHINE</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ab2ab9ef5e0fd2ad07b778d4453c6a180</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_DEFAULT_RTO</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga25beb3cb889e80636f91ed1e316ef083</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_DEFAULT_RC</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gaf2d937114195afa44a46b88b898a781b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_CONFLICT_ERROR_CODE</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a6fe14da13dbefeff267554a95245b0c3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_ice_ctx_s</type>
+ <name>tnet_ice_ctx_t</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a5337006422b6a6d5410461f964d6e3a9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_ice_action_s</type>
+ <name>tnet_ice_action_t</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a179dbc88e6e0fabf4f458f14aed80ea2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum _fsm_state_e</type>
+ <name>_fsm_state_t</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ac06f5d03925a1287a4f89e0d57f347fe</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum _fsm_action_e</type>
+ <name>_fsm_action_t</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>afe20aca1bd90c447e89dfd4b30661acf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>_fsm_state_e</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a92913a3e734277dfa8b96cdd97a9cbcb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_state_Started</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a92913a3e734277dfa8b96cdd97a9cbcba76034bb262163ff2e14ebbdbe3b3b2ba</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_state_GatheringHostCandidates</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a92913a3e734277dfa8b96cdd97a9cbcbac7bf056c75335dcdf2b754e0093a6186</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_state_GatheringHostCandidatesDone</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a92913a3e734277dfa8b96cdd97a9cbcba1b0f1991b1b431c4648a29a649752404</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_state_GatheringReflexiveCandidates</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a92913a3e734277dfa8b96cdd97a9cbcba7e0c8e38780560c73698c8cdefb6e280</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_state_GatheringReflexiveCandidatesDone</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a92913a3e734277dfa8b96cdd97a9cbcba9eb9e11bb1eb0cae53360c13058e440e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_state_GatheringCompleted</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a92913a3e734277dfa8b96cdd97a9cbcba65194ba2f9bb66c268ad079b11414e73</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_state_ConnChecking</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a92913a3e734277dfa8b96cdd97a9cbcbaad6e69dd6419d0e8da9eb42f03aa5240</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_state_ConnCheckingCompleted</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a92913a3e734277dfa8b96cdd97a9cbcbabcb7f6f071eb6a6ef27ab368a153cdba</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_state_Terminated</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a92913a3e734277dfa8b96cdd97a9cbcbaeab8f5e66ccc9c9df9e4edd20400e037</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>_fsm_action_e</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ad032147dfda9028e630a09a1c3bec61d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_action_Success</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ad032147dfda9028e630a09a1c3bec61da5635821eb87b10ae2cc08e32aac16cb5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_action_Failure</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ad032147dfda9028e630a09a1c3bec61da8a615bd3454c07df86bd9d900cc8ad76</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_action_GatherHostCandidates</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ad032147dfda9028e630a09a1c3bec61da1959b1a775dfc61f4a91016e3e69ca42</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_action_GatherReflexiveCandidates</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ad032147dfda9028e630a09a1c3bec61da161e59357719a7f611c796abc5b660b6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_action_GatheringComplet</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ad032147dfda9028e630a09a1c3bec61da523af28f3ff1ed15f5b8ce50f62eb4ef</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_action_ConnCheck</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ad032147dfda9028e630a09a1c3bec61da8e7bfe7f383fad3fc058d54eb52700de</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_action_Cancel</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ad032147dfda9028e630a09a1c3bec61da82d57ea2cca20e4afe702353cca10b27</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>_fsm_action_Error</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ad032147dfda9028e630a09a1c3bec61dac394d62ff536294f276acf0f0ba36dfe</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_ice_ctx_t *</type>
+ <name>tnet_ice_ctx_create</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a5ca9c2ad39aafb1c9134b3e70269399f</anchor>
+ <arglist>(tsk_bool_t is_ice_jingle, tsk_bool_t use_ipv6, tsk_bool_t use_rtcp, tsk_bool_t is_video, tnet_ice_callback_f callback, const void *userdata)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_set_userdata</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a5423751e16041a4ae2980a2e61fad527</anchor>
+ <arglist>(tnet_ice_ctx_t *self, const void *userdata)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_set_stun</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a56e2e0474a35f73d9ddf7d749bbed280</anchor>
+ <arglist>(tnet_ice_ctx_t *self, const char *server_addr, uint16_t server_port, const char *software, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_start</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>aed85886ca3d3f140810988d7ee43dac3</anchor>
+ <arglist>(tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_rtp_callback</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a5b542845608c288a53c97dd31ebc14db</anchor>
+ <arglist>(tnet_ice_ctx_t *self, tnet_ice_rtp_callback_f rtp_callback, const void *rtp_callback_data)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_set_concheck_timeout</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a1e715ce9adbcadcfe3695cc7441cf7f3</anchor>
+ <arglist>(tnet_ice_ctx_t *self, int64_t timeout)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_set_remote_candidates</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a63e833e5a438da0a2a50bcdbfa8f2240</anchor>
+ <arglist>(tnet_ice_ctx_t *self, const char *candidates, const char *ufrag, const char *pwd, tsk_bool_t is_controlling, tsk_bool_t is_ice_jingle)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_set_rtcpmux</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>aa9980c495bca6e6413fe8185742602e6</anchor>
+ <arglist>(tnet_ice_ctx_t *self, tsk_bool_t use_rtcpmux)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_size_t</type>
+ <name>tnet_ice_ctx_count_local_candidates</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a203a51c4d8c0f278dd17361df0ef2e53</anchor>
+ <arglist>(const tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_ctx_got_local_candidates</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a55ef5867dee0b10bba1a0d98f89d37e4</anchor>
+ <arglist>(const tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_ice_candidate_t *</type>
+ <name>tnet_ice_ctx_get_local_candidate_at</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a52868e342a03d64d13f7e2d98d1b6b6a</anchor>
+ <arglist>(const tnet_ice_ctx_t *self, tsk_size_t index)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_ctx_is_started</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a7839820b10a59e1bd58a3fccb1e4b4a3</anchor>
+ <arglist>(const tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_ctx_is_active</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>aa6432bc0167c9a5409e775e1bd119ccb</anchor>
+ <arglist>(const tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_ctx_is_connected</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a47ba1e31a451454ad9039db323af98aa</anchor>
+ <arglist>(const tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_ctx_is_can_send</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>ace07f467c6f2365594be25662d977de4</anchor>
+ <arglist>(const tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_ctx_is_can_recv</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>aa54f36ec73b95f5df1de849d5bcdb322</anchor>
+ <arglist>(const tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_ctx_use_ipv6</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>aa94d177fced068791fb4a8366985d7b4</anchor>
+ <arglist>(const tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_ctx_use_rtcp</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a362a7747e13d2a43f453c4a8574f2714</anchor>
+ <arglist>(const tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_get_nominated_symetric_candidates</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>af8debc0978b4c0647fe939050e28e533</anchor>
+ <arglist>(const tnet_ice_ctx_t *self, uint32_t comp_id, const tnet_ice_candidate_t **candidate_offer, const tnet_ice_candidate_t **candidate_answer_src, const tnet_ice_candidate_t **candidate_answer_dest)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_recv_stun_message</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a8576bba1c6e679901ba50dd4196f68a2</anchor>
+ <arglist>(tnet_ice_ctx_t *self, const void *data, tsk_size_t size, tnet_fd_t local_fd, const struct sockaddr_storage *remote_addr, tsk_bool_t *role_conflict)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_ice_ctx_get_ufrag</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>af4bb2eb46e5f830afa57bc3f205fda39</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_ice_ctx_get_pwd</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a3839f3ad301a60ed037d165ea96d0b8a</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_cancel</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a3f4609063f5e164bf179e9426147b268</anchor>
+ <arglist>(tnet_ice_ctx_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_ctx_stop</name>
+ <anchorfile>tnet__ice__ctx_8c.html</anchorfile>
+ <anchor>a408b03fe70b52c1956d5958ecd17a630</anchor>
+ <arglist>(tnet_ice_ctx_t *self)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice_ctx.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice__ctx_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <member kind="typedef">
+ <type>int(*</type>
+ <name>tnet_ice_callback_f</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a27ec12a843557e55a95a0fb1ecfa773b</anchor>
+ <arglist>)(const struct tnet_ice_event_s *e)</arglist>
+ </member>
+ <member kind="typedef">
+ <type>int(*</type>
+ <name>tnet_ice_rtp_callback_f</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a5663852680900fb56fac193335da7e1d</anchor>
+ <arglist>)(const void *callback_data, const uint8_t *data_ptr, tsk_size_t data_size, tnet_fd_t local_fd, const struct sockaddr_storage *remote_addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API struct tnet_ice_ctx_s *</type>
+ <name>tnet_ice_ctx_create</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a12ee5c476bd9dbde49a91859c009acdc</anchor>
+ <arglist>(tsk_bool_t is_ice_jingle, tsk_bool_t use_ipv6, tsk_bool_t use_rtcp, tsk_bool_t is_video, tnet_ice_callback_f callback, const void *userdata)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_set_userdata</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a755c575a5ed684bf9a8f725e723d7e9b</anchor>
+ <arglist>(struct tnet_ice_ctx_s *self, const void *userdata)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_set_stun</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a9810feb9fc3f4b65cddcc0ae4f9cdf91</anchor>
+ <arglist>(struct tnet_ice_ctx_s *self, const char *server_addr, uint16_t server_port, const char *software, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_start</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>ad22f9137c77b1ec27d3a2e113ebc24ab</anchor>
+ <arglist>(struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_rtp_callback</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a483946fd722c8e7abb679842a9a9680f</anchor>
+ <arglist>(struct tnet_ice_ctx_s *self, tnet_ice_rtp_callback_f rtp_callback, const void *rtp_callback_data)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_set_concheck_timeout</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a7c9ee53291152f8305b5286192a2e065</anchor>
+ <arglist>(struct tnet_ice_ctx_s *self, int64_t timeout)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_set_remote_candidates</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a3898ece620d9e4b7aac8dd782c32192c</anchor>
+ <arglist>(struct tnet_ice_ctx_s *self, const char *candidates, const char *ufrag, const char *pwd, tsk_bool_t is_controlling, tsk_bool_t is_ice_jingle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_set_rtcpmux</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a40521555048afd300d4b25daa623f1cd</anchor>
+ <arglist>(struct tnet_ice_ctx_s *self, tsk_bool_t use_rtcpmux)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_size_t</type>
+ <name>tnet_ice_ctx_count_local_candidates</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a1df3093c5795ce6d3d53a8eb2080be5e</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_ice_ctx_got_local_candidates</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a847a4b0980b025c73dacb6348896ae20</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API struct tnet_ice_candidate_s *</type>
+ <name>tnet_ice_ctx_get_local_candidate_at</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a911f1de5737af15363c06a1b461496a9</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self, tsk_size_t index)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_ice_ctx_is_started</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a282bdc4713a8bc105ee5ab2674f62bc6</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_ice_ctx_is_active</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>adcaaff8a00a20dfd5d189f2f7db558ef</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_ice_ctx_is_connected</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>aea90d2adab4f24e325bca5d5d89cdfb6</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_ice_ctx_is_can_send</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>aa648ed1192ae6efe86fc5f6cf3d5b612</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_ice_ctx_is_can_recv</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>aa05115be04d05a7b9e691afa566d3fc3</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_ice_ctx_use_ipv6</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>aa8e3918e531c841cd836d8adafea12c4</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_ice_ctx_use_rtcp</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a07737c773d683cb497790a988cb1ebf9</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_get_nominated_symetric_candidates</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>ace906c0ae2a2a54a1690ec7d3918d304</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self, uint32_t comp_id, const struct tnet_ice_candidate_s **candidate_offer, const struct tnet_ice_candidate_s **candidate_answer_src, const struct tnet_ice_candidate_s **candidate_answer_dest)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_recv_stun_message</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>adb56901e00a28eed02082636b67799b8</anchor>
+ <arglist>(struct tnet_ice_ctx_s *self, const void *data, tsk_size_t size, tnet_fd_t local_fd, const struct sockaddr_storage *remote_addr, tsk_bool_t *role_conflict)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API const char *</type>
+ <name>tnet_ice_ctx_get_ufrag</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a6110b9ac7acef0309f2001017bc429eb</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API const char *</type>
+ <name>tnet_ice_ctx_get_pwd</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>a57e4ecac36e4347afdd7e8ec7ea293fb</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_cancel</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>acfb50b643529ac2786ea877b8deb7bea</anchor>
+ <arglist>(struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_ice_ctx_stop</name>
+ <anchorfile>tnet__ice__ctx_8h.html</anchorfile>
+ <anchor>afa968e2e280b850087de96990ea6d2fd</anchor>
+ <arglist>(struct tnet_ice_ctx_s *self)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice_event.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice__event_8c</filename>
+ <includes id="tnet__ice__event_8h" name="tnet_ice_event.h" local="yes" imported="no">tnet_ice_event.h</includes>
+ <member kind="function">
+ <type>tnet_ice_event_t *</type>
+ <name>tnet_ice_event_create</name>
+ <anchorfile>tnet__ice__event_8c.html</anchorfile>
+ <anchor>a77cbab4b4330794f85d9eb5273c058ec</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *ctx, tnet_ice_event_type_t type, const char *phrase, const void *userdata)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_event_set_action</name>
+ <anchorfile>tnet__ice__event_8c.html</anchorfile>
+ <anchor>aaa5b3edfeec0d647b25dc6acfd06ff6e</anchor>
+ <arglist>(tnet_ice_event_t *self, struct tnet_ice_action_s *action)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_ice_event_def_t</name>
+ <anchorfile>tnet__ice__event_8c.html</anchorfile>
+ <anchor>a25e7d74caa3ad2b9dcd4ae867e5df04d</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice_event.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice__event_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <class kind="struct">tnet_ice_event_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS enum tnet_ice_event_type_e</type>
+ <name>tnet_ice_event_type_t</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a975b8ce3f09b4e1472b0b14500f20f7e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_ice_event_s</type>
+ <name>tnet_ice_event_t</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a0390cfd3c36181301f676cf6a78c5d62</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_ice_event_type_e</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_started</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618caf2dea4d71ac8de9c60542876a4e36582</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_start_failed</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618cacb800acde7ad4618439f914565fef7be</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_stopped</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618ca51db6ab0e95e5de86c99df1411cfacaa</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_stop_failed</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618ca4575cdfcaa7d3d2361cc9f739ebe8afd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_gathering_host_candidates_failed</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618ca0fb6cfc0f458b79541b161acda4c0821</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_gathering_host_candidates_succeed</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618ca475effc574a2ffae5ab99ebcbb3feb09</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_gathering_reflexive_candidates_failed</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618ca71124ba92e03873ec44f1536c89ae9a7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_gathering_reflexive_candidates_succeed</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618ca5a2e9fc2e3f239d84e6182c15a4ad158</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_gathering_completed</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618ca279c70a496fad0887bb6210b26b72ad3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_conncheck_succeed</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618ca4e0d385966d85596916ae77d7c05d68e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_conncheck_failed</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618ca0769a7f9355a5fdf3adb31227f86992a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_cancelled</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618ca38cc53ca1eb9e56d1c1f50707648c7fe</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_event_type_action</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a994d6e614c765273d8a18c4f2f25618cab79c4a6d366909e30fd37f07705d3f7c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_ice_event_t *</type>
+ <name>tnet_ice_event_create</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>a77cbab4b4330794f85d9eb5273c058ec</anchor>
+ <arglist>(const struct tnet_ice_ctx_s *ctx, tnet_ice_event_type_t type, const char *phrase, const void *userdata)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_event_set_action</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>aaa5b3edfeec0d647b25dc6acfd06ff6e</anchor>
+ <arglist>(tnet_ice_event_t *self, struct tnet_ice_action_s *action)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_ice_event_def_t</name>
+ <anchorfile>tnet__ice__event_8h.html</anchorfile>
+ <anchor>aa28619d31a504bbda6e2216cc753edd7</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice_pair.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice__pair_8c</filename>
+ <includes id="tnet__ice__pair_8h" name="tnet_ice_pair.h" local="yes" imported="no">tnet_ice_pair.h</includes>
+ <includes id="tnet__ice__utils_8h" name="tnet_ice_utils.h" local="yes" imported="no">tnet_ice_utils.h</includes>
+ <includes id="tnet__ice__candidate_8h" name="tnet_ice_candidate.h" local="yes" imported="no">tnet_ice_candidate.h</includes>
+ <includes id="tnet__stun_8h" name="tnet_stun.h" local="yes" imported="no">stun/tnet_stun.h</includes>
+ <includes id="tnet__stun__message_8h" name="tnet_stun_message.h" local="yes" imported="no">stun/tnet_stun_message.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">tnet_endianness.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_PAIR_FULL_DEBUG</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>af56c18fe90446697a5fc4d3dc0141a31</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_PAIR_DEBUG_INFO</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a4a20a7b0344e3395289e4d2a91df2871</anchor>
+ <arglist>(...)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>_tnet_ice_pairs_none_succeed_answer</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a91556bbcaf447b1a1def8f41ba42268b</anchor>
+ <arglist>(pairs, comp_id, foundation)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>_tnet_ice_pairs_none_succeed_offer</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>ad60742a24a92d792c2819155da19b8d9</anchor>
+ <arglist>(pairs, comp_id, foundation)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>_tnet_ice_pairs_get_nominated_offer_at</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a94bbca3121738958a49e6548361185cb</anchor>
+ <arglist>(pairs, index, comp_id, check_fullness, ret)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>_tnet_ice_pairs_get_nominated_answer_at</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>af8bd4c48cf08abaf5c1411e548eb2327</anchor>
+ <arglist>(pairs, index, comp_id, check_fullness, ret)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>_tnet_ice_pairs_get_nominated_at</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a7a7acb9867360b14dd28fb7778a367cd</anchor>
+ <arglist>(pairs, dir_1, dir_2, index, _comp_id, check_fullness, ret)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_ice_pair_t *</type>
+ <name>tnet_ice_pair_create</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a9954ff5858e695dc00daa4fedceef7bc</anchor>
+ <arglist>(const tnet_ice_candidate_t *candidate_offer, const tnet_ice_candidate_t *candidate_answer, tsk_bool_t is_controlling, uint64_t tie_breaker, tsk_bool_t is_ice_jingle)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_ice_pair_t *</type>
+ <name>tnet_ice_pair_prflx_create</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>ab216201ed60c63e86ccdbac02bc25841</anchor>
+ <arglist>(tnet_ice_pairs_L_t *pairs, uint16_t local_fd, const struct sockaddr_storage *remote_addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_pair_send_conncheck</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a85c6042e32b7b9cf53b7fa7e0bcc426f</anchor>
+ <arglist>(tnet_ice_pair_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_pair_send_response</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a5df18532be4825241faefee37ee03225</anchor>
+ <arglist>(tnet_ice_pair_t *self, const tnet_stun_request_t *request, const short code, const char *phrase, const struct sockaddr_storage *remote_addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_pair_auth_conncheck</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a66ac3130aa0e23a7afd19626cb672ae5</anchor>
+ <arglist>(const tnet_ice_pair_t *self, const tnet_stun_request_t *request, const void *request_buff, tsk_size_t request_buff_size, short *resp_code, char **resp_phrase)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_pair_recv_response</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a677afd408bd9b486277f3b7565143b30</anchor>
+ <arglist>(tnet_ice_pair_t *self, const tnet_stun_response_t *response)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_ice_pair_t *</type>
+ <name>tnet_ice_pairs_find_by_response</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a01153e3a78f12fcb8624b7bd220be109</anchor>
+ <arglist>(tnet_ice_pairs_L_t *pairs, const tnet_stun_message_t *response)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_ice_pair_t *</type>
+ <name>tnet_ice_pairs_find_by_fd_and_addr</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>ab4af64f71b6d5cb647bd1dfa06cd1f55</anchor>
+ <arglist>(tnet_ice_pairs_L_t *pairs, uint16_t local_fd, const struct sockaddr_storage *remote_addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_pairs_have_nominated_offer</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a7b1fe8483a52a82f8991df84072cb2d6</anchor>
+ <arglist>(const tnet_ice_pairs_L_t *pairs, tsk_bool_t check_rtcp)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_pairs_have_nominated_answer</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>acb27f1ec09cbca2e5741bcf725dc0554</anchor>
+ <arglist>(const tnet_ice_pairs_L_t *pairs, tsk_bool_t check_rtcp)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_pairs_have_nominated_symetric</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a2a13d75cb4dbe073c33f39866522bc7b</anchor>
+ <arglist>(const tnet_ice_pairs_L_t *pairs, tsk_bool_t check_rtcp)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_pairs_get_nominated_symetric</name>
+ <anchorfile>tnet__ice__pair_8c.html</anchorfile>
+ <anchor>a66edabbbb2d10827fa8e5b1a016a757d</anchor>
+ <arglist>(const tnet_ice_pairs_L_t *pairs, uint32_t comp_id, const tnet_ice_candidate_t **candidate_offer, const tnet_ice_candidate_t **candidate_answer_src, const tnet_ice_candidate_t **candidate_answer_dest)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice_pair.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice__pair_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <class kind="struct">tnet_ice_pair_s</class>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_ice_pairs_L_t</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>ac830cf0356d199d5a0c4ef65b6f82271</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_ice_pair_state_e</type>
+ <name>tnet_ice_pair_state_t</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a83c4d1c62e53329dacef0b1ad5248800</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_ice_pair_s</type>
+ <name>tnet_ice_pair_t</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>af480f16d58e42c4530c35be2369071fe</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_ice_pair_state_e</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a14944762848a13004196843f3247d4fa</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_pair_state_frozen</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a14944762848a13004196843f3247d4faa96505cd6b130519ff496ddead305f015</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_pair_state_waiting</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a14944762848a13004196843f3247d4faaf0de95577da0434c3c14a34ae8784626</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_pair_state_in_progress</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a14944762848a13004196843f3247d4faaf7210c9f40a6004b8ac784539b3cc33f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_pair_state_succeed</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a14944762848a13004196843f3247d4faaa2fd1062153893d0cfe21af4c4ed7858</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_ice_pair_state_failed</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a14944762848a13004196843f3247d4faa50dcec8ceca592e1b285319d481e5433</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_ice_pair_t *</type>
+ <name>tnet_ice_pair_create</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>ab5af472e9d0b64eccbd2c7ff6ae00569</anchor>
+ <arglist>(const struct tnet_ice_candidate_s *candidate_offer, const struct tnet_ice_candidate_s *candidate_answer, tsk_bool_t is_controlling, uint64_t tie_breaker, tsk_bool_t is_ice_jingle)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_ice_pair_t *</type>
+ <name>tnet_ice_pair_prflx_create</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>ab216201ed60c63e86ccdbac02bc25841</anchor>
+ <arglist>(tnet_ice_pairs_L_t *pairs, uint16_t local_fd, const struct sockaddr_storage *remote_addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_pair_send_conncheck</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a85c6042e32b7b9cf53b7fa7e0bcc426f</anchor>
+ <arglist>(tnet_ice_pair_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_pair_send_response</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>aab77228c7d44cc1d6fce074d87ec1d14</anchor>
+ <arglist>(tnet_ice_pair_t *self, const struct tnet_stun_message_s *request, const short code, const char *phrase, const struct sockaddr_storage *remote_addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_pair_auth_conncheck</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>adb20520b5d6265211ef5f50e68b5db67</anchor>
+ <arglist>(const tnet_ice_pair_t *self, const struct tnet_stun_message_s *request, const void *request_buff, tsk_size_t request_buff_size, short *resp_code, char **resp_phrase)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_pair_recv_response</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a45bac2585f4e128e950b650e4178cce6</anchor>
+ <arglist>(tnet_ice_pair_t *self, const struct tnet_stun_message_s *response)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_ice_pair_t *</type>
+ <name>tnet_ice_pairs_find_by_response</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a252eab33e96ac1a00b324c04f09f6302</anchor>
+ <arglist>(tnet_ice_pairs_L_t *pairs, const struct tnet_stun_message_s *response)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_ice_pair_t *</type>
+ <name>tnet_ice_pairs_find_by_fd_and_addr</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>ab4af64f71b6d5cb647bd1dfa06cd1f55</anchor>
+ <arglist>(tnet_ice_pairs_L_t *pairs, uint16_t local_fd, const struct sockaddr_storage *remote_addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_pairs_have_nominated_offer</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a7b1fe8483a52a82f8991df84072cb2d6</anchor>
+ <arglist>(const tnet_ice_pairs_L_t *pairs, tsk_bool_t check_rtcp)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_pairs_have_nominated_answer</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>acb27f1ec09cbca2e5741bcf725dc0554</anchor>
+ <arglist>(const tnet_ice_pairs_L_t *pairs, tsk_bool_t check_rtcp)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_ice_pairs_have_nominated_symetric</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a2a13d75cb4dbe073c33f39866522bc7b</anchor>
+ <arglist>(const tnet_ice_pairs_L_t *pairs, tsk_bool_t check_rtcp)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_pairs_get_nominated_symetric</name>
+ <anchorfile>tnet__ice__pair_8h.html</anchorfile>
+ <anchor>a511052e10a99af4091c493efafe89834</anchor>
+ <arglist>(const tnet_ice_pairs_L_t *pairs, uint32_t comp_id, const struct tnet_ice_candidate_s **candidate_offer, const struct tnet_ice_candidate_s **candidate_answer_src, const struct tnet_ice_candidate_s **candidate_answer_dest)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice_utils.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice__utils_8c</filename>
+ <includes id="tnet__ice__utils_8h" name="tnet_ice_utils.h" local="yes" imported="no">tnet_ice_utils.h</includes>
+ <includes id="tnet__ice__candidate_8h" name="tnet_ice_candidate.h" local="yes" imported="no">tnet_ice_candidate.h</includes>
+ <includes id="tnet__socket_8h" name="tnet_socket.h" local="yes" imported="no">tnet_socket.h</includes>
+ <member kind="function">
+ <type>uint32_t</type>
+ <name>tnet_ice_utils_get_priority</name>
+ <anchorfile>tnet__ice__utils_8c.html</anchorfile>
+ <anchor>aa9f6decbe3be7f3e6e053ac5eccbc006</anchor>
+ <arglist>(tnet_ice_cand_type_t type, uint16_t local_pref, tsk_bool_t is_rtp)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_utils_compute_foundation</name>
+ <anchorfile>tnet__ice__utils_8c.html</anchorfile>
+ <anchor>a20aa1508b722706b3f79a66fd6cf1f53</anchor>
+ <arglist>(char *foundation, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_utils_create_sockets</name>
+ <anchorfile>tnet__ice__utils_8c.html</anchorfile>
+ <anchor>a036f56c1171682aeaa8afe0b38c3e213</anchor>
+ <arglist>(tnet_socket_type_t socket_type, const char *local_ip, tnet_socket_t **socket_rtp, tnet_socket_t **socket_rtcp)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_utils_stun_address_tostring</name>
+ <anchorfile>tnet__ice__utils_8c.html</anchorfile>
+ <anchor>aa4b1d320ede078f895b468b654bb1547</anchor>
+ <arglist>(const uint8_t in_ip[16], enum tnet_stun_addr_family_e family, char **out_ip)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_utils_set_ufrag</name>
+ <anchorfile>tnet__ice__utils_8c.html</anchorfile>
+ <anchor>a3a67080a7126486eb3851b1b1ccdb13c</anchor>
+ <arglist>(char **ufrag)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_utils_set_pwd</name>
+ <anchorfile>tnet__ice__utils_8c.html</anchorfile>
+ <anchor>ae3494b188d4676184783f3431eefc91f</anchor>
+ <arglist>(char **pwd)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_ice_utils.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>tnet__ice__utils_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <member kind="function">
+ <type>uint32_t</type>
+ <name>tnet_ice_utils_get_priority</name>
+ <anchorfile>tnet__ice__utils_8h.html</anchorfile>
+ <anchor>a0a76443414a9f5fb9ca22e5b1efd0527</anchor>
+ <arglist>(enum tnet_ice_cand_type_e type, uint16_t local_pref, tsk_bool_t is_rtp)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_utils_compute_foundation</name>
+ <anchorfile>tnet__ice__utils_8h.html</anchorfile>
+ <anchor>a20aa1508b722706b3f79a66fd6cf1f53</anchor>
+ <arglist>(char *foundation, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_utils_create_sockets</name>
+ <anchorfile>tnet__ice__utils_8h.html</anchorfile>
+ <anchor>aaea4db85c414e483888ad84b462fe128</anchor>
+ <arglist>(enum tnet_socket_type_e socket_type, const char *local_ip, struct tnet_socket_s **socket_rtp, struct tnet_socket_s **socket_rtcp)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_utils_stun_address_tostring</name>
+ <anchorfile>tnet__ice__utils_8h.html</anchorfile>
+ <anchor>aa4b1d320ede078f895b468b654bb1547</anchor>
+ <arglist>(const uint8_t in_ip[16], enum tnet_stun_addr_family_e family, char **out_ip)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_utils_set_ufrag</name>
+ <anchorfile>tnet__ice__utils_8h.html</anchorfile>
+ <anchor>a3a67080a7126486eb3851b1b1ccdb13c</anchor>
+ <arglist>(char **ufrag)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_ice_utils_set_pwd</name>
+ <anchorfile>tnet__ice__utils_8h.html</anchorfile>
+ <anchor>ae3494b188d4676184783f3431eefc91f</anchor>
+ <arglist>(char **pwd)</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_stun.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/stun/</path>
+ <filename>tnet__stun_8c</filename>
+ <includes id="tnet__stun_8h" name="tnet_stun.h" local="yes" imported="no">tnet_stun.h</includes>
+ <includes id="tnet__nat_8h" name="tnet_nat.h" local="yes" imported="no">../tnet_nat.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">../tnet_utils.h</includes>
+ <member kind="function">
+ <type>tnet_stun_binding_t *</type>
+ <name>tnet_stun_binding_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga60801a4caec4d4335f0b4fea0e63025e</anchor>
+ <arglist>(tnet_fd_t fd, tnet_socket_type_t socket_type, const char *server_address, tnet_port_t server_port, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_message_t *</type>
+ <name>tnet_stun_create_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga481bcd3d5bfdfda6561227bfcf1fc359</anchor>
+ <arglist>(const tnet_stun_binding_t *binding)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_send_reliably</name>
+ <anchorfile>tnet__stun_8c.html</anchorfile>
+ <anchor>a237dcc868a064df02b762deab4137f3f</anchor>
+ <arglist>(const tnet_stun_message_t *message)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_response_t *</type>
+ <name>tnet_stun_send_unreliably</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga36147911b3c99cbf897930c971608a5f</anchor>
+ <arglist>(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const tnet_stun_message_t *message, struct sockaddr *server)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_send_bind</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8151700d692ca34abf3cd42982723aa7</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_stun_binding_t *binding)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_binding_id_t</type>
+ <name>tnet_stun_bind</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gafad0d44c67c44e0cf91de149a32e8079</anchor>
+ <arglist>(const tnet_nat_context_t *nat_context, tnet_fd_t localFD)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_transacid_cmp</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gad2cd556a7d81575118646c3e3002af66</anchor>
+ <arglist>(const tnet_stun_transacid_t id1, const tnet_stun_transacid_t id2)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_binding_def_t</name>
+ <anchorfile>tnet__stun_8c.html</anchorfile>
+ <anchor>a0dd86286d48f57fdd7107fd84788f79a</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_stun.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/stun/</path>
+ <filename>tnet__stun_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__stun__message_8h" name="tnet_stun_message.h" local="yes" imported="no">stun/tnet_stun_message.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <includes id="tnet__socket_8h" name="tnet_socket.h" local="yes" imported="no">tnet_socket.h</includes>
+ <class kind="struct">tnet_stun_binding_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_INVALID_BINDING_ID</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaeb338f5c8a9b3ac08bba78293fdc22d4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_IS_VALID_BINDING_ID</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga809cd1386eaa84094e78ef17a414ad7d</anchor>
+ <arglist>(id)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_TCP_UDP_DEFAULT_PORT</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga840d6af2bf3bd3a96d120c942abefd7a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_TLS_DEFAULT_PORT</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab0ae6bc64ad691f9bc5bd2b4c88c4569</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_MAGIC_COOKIE</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gac5e54e4b4576b54b53d2f4242f3e30de</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_HEADER_SIZE</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga1df2b74747811b1bbdad28b18e0d80c3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_binding_s</type>
+ <name>tnet_stun_binding_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gabb378355a46b1aef733acdeef3a38368</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_stun_bindings_L_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga994b6db4d6ac6e78c4ece450f1d5edff</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_send_reliably</name>
+ <anchorfile>tnet__stun_8h.html</anchorfile>
+ <anchor>a237dcc868a064df02b762deab4137f3f</anchor>
+ <arglist>(const tnet_stun_message_t *message)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_response_t *</type>
+ <name>tnet_stun_send_unreliably</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga36147911b3c99cbf897930c971608a5f</anchor>
+ <arglist>(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const tnet_stun_message_t *message, struct sockaddr *server)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_binding_id_t</type>
+ <name>tnet_stun_bind</name>
+ <anchorfile>tnet__stun_8h.html</anchorfile>
+ <anchor>af34e4d8f55deb66b7ff5414552a7e9e6</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, tnet_fd_t localFD)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_transacid_cmp</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gad2cd556a7d81575118646c3e3002af66</anchor>
+ <arglist>(const tnet_stun_transacid_t id1, const tnet_stun_transacid_t id2)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TNET_BEGIN_DECLS typedef uint64_t</type>
+ <name>tnet_stun_binding_id_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab95871f186b8bf46b4630ab2ebb146aa</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_binding_def_t</name>
+ <anchorfile>tnet__stun_8h.html</anchorfile>
+ <anchor>acaa4cac3d3d802dd9090d36d6a7dd465</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_stun_attribute.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/stun/</path>
+ <filename>tnet__stun__attribute_8c</filename>
+ <includes id="tnet__stun__attribute_8h" name="tnet_stun_attribute.h" local="yes" imported="no">tnet_stun_attribute.h</includes>
+ <includes id="tnet__stun_8h" name="tnet_stun.h" local="yes" imported="no">tnet_stun.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <includes id="tnet__turn__attribute_8h" name="tnet_turn_attribute.h" local="yes" imported="no">../turn/tnet_turn_attribute.h</includes>
+ <member kind="function">
+ <type>tnet_stun_attribute_t *</type>
+ <name>tnet_stun_attribute_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga9a8fea6f7fb4c6236bc4df85153d6af4</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_mapped_addr_t *</type>
+ <name>tnet_stun_attribute_mapped_address_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga28ffe32f830bbe0f5b32a207538eb8b6</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_xmapped_addr_t *</type>
+ <name>tnet_stun_attribute_xmapped_address_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gacd4af1df8c9e298a23d34df27e5dcc45</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_username_t *</type>
+ <name>tnet_stun_attribute_username_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab92c8f62b2d188c9ac1528aa03da4b7e</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_integrity_t *</type>
+ <name>tnet_stun_attribute_integrity_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3c5f79313850ea8643132b093e11ef6a</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_fingerprint_t *</type>
+ <name>tnet_stun_attribute_fingerprint_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga2432db4c4bb63da2327bb357361eef21</anchor>
+ <arglist>(uint32_t fingerprint)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_errorcode_t *</type>
+ <name>tnet_stun_attribute_errorcode_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaa51e8bc565195298fb3de24070f5614a</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_realm_t *</type>
+ <name>tnet_stun_attribute_realm_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga2d7ab50986b3af03951358ec4c2cfa8b</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_nonce_t *</type>
+ <name>tnet_stun_attribute_nonce_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga0cf404a4977b95a47c252f8101b099ce</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_unknowns_t *</type>
+ <name>tnet_stun_attribute_unknowns_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8a497b2b11b1a776ec37170ee14b6ac2</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_software_t *</type>
+ <name>tnet_stun_attribute_software_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga719d8c3ac6588124533f03f70877e437</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_altserver_t *</type>
+ <name>tnet_stun_attribute_altserver_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga586636541b8ebb9ea46d4df39a448121</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_ice_priority_t *</type>
+ <name>tnet_stun_attribute_ice_priority_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7e2992cbcf5e4d93fce285c8fdad6018</anchor>
+ <arglist>(uint32_t value)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_ice_use_candidate_t *</type>
+ <name>tnet_stun_attribute_ice_use_candidate_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gafc6efba58197cb3d697502bbad7378cf</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_ice_controlled_t *</type>
+ <name>tnet_stun_attribute_ice_controlled_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaf2e4854c90f7c8c3abae9915e59ad12f</anchor>
+ <arglist>(uint64_t value)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_ice_controlling_t *</type>
+ <name>tnet_stun_attribute_ice_controlling_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga94da0e7a21d255c8647c190387229ba3</anchor>
+ <arglist>(uint64_t value)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_t *</type>
+ <name>tnet_stun_attribute_deserialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga642d9b382cea0cbbf0590b8b60be54c6</anchor>
+ <arglist>(const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_attribute_serialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gabb81a19c0eeb9f47f0b9599d65d61d6e</anchor>
+ <arglist>(const tnet_stun_attribute_t *attribute, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>void</type>
+ <name>tnet_stun_attribute_pad</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga9364909d8a9c38fa1be0dd48efa3fac3</anchor>
+ <arglist>(const tnet_stun_attribute_t *attribute, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>a39de14fd624ed0daca8ee80b3b788167</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_mapped_addr_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>a2069575f6768e7dbf84b722ab49e2092</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_xmapped_addr_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>aafd262dbecb13f75062287d1a53f79cb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_username_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>a061d0206949d7884f94db65fd4d13ff8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_integrity_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>adb93c2f122fac924c896e1d6e41dee12</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_fingerprint_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>a1a8d87cb810361528f08db9ac6ad08d3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_errorcode_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>ae68e0c928ed436d9f61f3924b5bc937f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_realm_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>a7e250a9748696036a59bd90577a803eb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_nonce_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>aa0af7d26bae0b56988d370be6640c1c2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_unknowns_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>a78dfa6acb03b4b2097cb5cdf1cfc7559</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_software_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>a2b6d86a4a4f4ce12b7053a8804b6b773</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_altserver_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>ad40ed47dfee2cb3133324064dce05d37</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_ice_priority_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>a1c25a2b5a16a48e1c229f81e0f0cf1ed</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_ice_use_candidate_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>aef82b09b0928979e9559be947d4a2f4b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_ice_controlled_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>a975b2da5a481b51af116f5a3775f2889</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_ice_controlling_def_t</name>
+ <anchorfile>tnet__stun__attribute_8c.html</anchorfile>
+ <anchor>a684b7fd78ca1f9002093ac01b5792600</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_stun_attribute.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/stun/</path>
+ <filename>tnet__stun__attribute_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <class kind="struct">tnet_stun_attribute_s</class>
+ <class kind="struct">tnet_stun_attribute_mapped_addr_s</class>
+ <class kind="struct">tnet_stun_attribute_xmapped_addr_s</class>
+ <class kind="struct">tnet_stun_attribute_username_s</class>
+ <class kind="struct">tnet_stun_attribute_integrity_s</class>
+ <class kind="struct">tnet_stun_attribute_fingerprint_s</class>
+ <class kind="struct">tnet_stun_attribute_errorcode_s</class>
+ <class kind="struct">tnet_stun_attribute_realm_s</class>
+ <class kind="struct">tnet_stun_attribute_nonce_s</class>
+ <class kind="struct">tnet_stun_attribute_unknowns_s</class>
+ <class kind="struct">tnet_stun_attribute_software_s</class>
+ <class kind="struct">tnet_stun_attribute_altserver_s</class>
+ <class kind="struct">tnet_stun_attribute_ice_priority_s</class>
+ <class kind="struct">tnet_stun_attribute_ice_use_candidate_s</class>
+ <class kind="struct">tnet_stun_attribute_ice_controlled_s</class>
+ <class kind="struct">tnet_stun_attribute_ice_controlling_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_ATTRIBUTE</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaeec0275bf11e81b2b89c149df5194c51</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a62f9fefaa02d86218a754f2f8f9d9b68</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_stun_addr_family_e</type>
+ <name>tnet_stun_addr_family_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7080ca2a8d2b45a22d21c522a2a5a28f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_stun_attribute_type_e</type>
+ <name>tnet_stun_attribute_type_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga2e77e50a4af676b754191403ae102933</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_s</type>
+ <name>tnet_stun_attribute_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3ce2a25dae1324a8dd545a68a2d8ccf3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_stun_attributes_L_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a423021672c1cb1cfc6e87418925fee9d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_mapped_addr_s</type>
+ <name>tnet_stun_attribute_mapped_addr_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga6ef5c5c6d47376dc7cf7ac14b923ad26</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_xmapped_addr_s</type>
+ <name>tnet_stun_attribute_xmapped_addr_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8885759ce02dd0bebc0bee97ec48171c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_username_s</type>
+ <name>tnet_stun_attribute_username_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga33d875930c4e6213e7516e580a88eebb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_integrity_s</type>
+ <name>tnet_stun_attribute_integrity_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8b2b266a46e44c471708eca71ac8670a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_fingerprint_s</type>
+ <name>tnet_stun_attribute_fingerprint_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7ead14f441ddf014894c17fcef2feeaf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_errorcode_s</type>
+ <name>tnet_stun_attribute_errorcode_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga0e804aae488d73e576dd9c4453a93a04</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_realm_s</type>
+ <name>tnet_stun_attribute_realm_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaaf4ef4fa43bec46b6313c0c400d6c6ca</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_nonce_s</type>
+ <name>tnet_stun_attribute_nonce_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7e4d37384aa42524d68d8e9e0ddc9ea2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_unknowns_s</type>
+ <name>tnet_stun_attribute_unknowns_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab27dd830e06e223350a584c41383015d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_software_s</type>
+ <name>tnet_stun_attribute_software_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga5744df35d8bf1f1f366097f6a63f1177</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_altserver_s</type>
+ <name>tnet_stun_attribute_altserver_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga1912ae8bc9ea407a04f1d16aa570dbc9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_ice_priority_s</type>
+ <name>tnet_stun_attribute_ice_priority_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga782dcf37c6503a9287b479cef6fe0132</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_ice_use_candidate_s</type>
+ <name>tnet_stun_attribute_ice_use_candidate_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga47de3ced777b9c46f863e513b934ab23</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_ice_controlled_s</type>
+ <name>tnet_stun_attribute_ice_controlled_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab46c08e93d0c514a72fc8b3f73bc7a77</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_ice_controlling_s</type>
+ <name>tnet_stun_attribute_ice_controlling_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gac4832ed589696b4a9ef6274b96333adf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_stun_addr_family_e</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3326fbcc063f264d3d359e922637e2e4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ipv4</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3326fbcc063f264d3d359e922637e2e4a5663f4b60301ed2f9e7823613407dbed</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ipv6</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3326fbcc063f264d3d359e922637e2e4a97e1e424d39a8af2791c1187090f111e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_stun_attribute_type_e</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab696586b61219965987af1e017e6ffa6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_reserved</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a5bf34ce06a004ad9f8db1dc687786273</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_mapped_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a9aadc5f8467c936cc7359889ba120e33</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_response_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a203b0a7edf4f8fb3381ac769595a2098</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_change_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6aeb35b7b83152b7a99bf46b4014928adc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_source_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a69f3448100d4f1a61536eb2c7315cd90</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_changed_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a0bd0d2c8f1d6ae85ffb58aeef4c01134</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_username</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a3247970572dad0c63e537b647dbd0861</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_password</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a432698b7b67cf13adf504f969abb60fd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_message_integrity</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ac20851e6e8fd2c479c0438b376987a85</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_error_code</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ab8571c9a5c334530ef9aa45adc7fd71e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_unknown_attributes</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a455d442e5c380953ff11c7e0d055f3ae</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_reflected_from</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ae129dfcf945fe995400dba3e8b9895c5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_realm</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a0d8e28c40313d6d3b397ac957714cfee</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_nonce</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ae5dda080590c37e95953334f715ed3ef</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_xor_mapped_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6af70dcad086bff5d4ee77f093941642d2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_software</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ad5a2f9a89fbc825142e4d754b51bc125</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_alternate_server</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a4f263d754aaccf30fd861a934dfc12ba</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_fingerprint</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6aac669613b66507fba6c08d23a4283bf2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_channel_number</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a7559421f1d46a400cdda94c32c3aff74</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_lifetime</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6aff4ed6f5e451f77b39d5113b9085493c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_reserved2</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a626c6684c81f69c1649e178cc9847069</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_xor_peer_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ae14d3b3903934eab51356ad28584fc66</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_data</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ab85dfed04ff37affea00d10a517c72dd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_xor_relayed_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ada0a3d93b81c32a3d0af2ed20efffe71</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_even_port</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ac99da9ae2b9a6a885631e5e476293df2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_requested_transport</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a033a9a9cdad515c45291007be25dd028</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_dont_fragment</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a3f854135f19b767abc7e8031af6b5f88</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_reserved3</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a57c9e8d7229d0989d73a5efc2fef36e7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_reservation_token</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a88373f0f1635103b2091910a9584c58d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ice_priority</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a99410d8e75f7ab0d4421fe71634604bb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ice_use_candidate</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a275c187aabe3a9d9bdc32a180c39b1d2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ice_controlled</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a4cfd4eab6287ed2b1126e6ba40ac5d4a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ice_controlling</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a21100a7a716c88ed5b5544cdb28549aa</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_t *</type>
+ <name>tnet_stun_attribute_deserialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga642d9b382cea0cbbf0590b8b60be54c6</anchor>
+ <arglist>(const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_attribute_serialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gabb81a19c0eeb9f47f0b9599d65d61d6e</anchor>
+ <arglist>(const tnet_stun_attribute_t *attribute, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>void</type>
+ <name>tnet_stun_attribute_pad</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga9364909d8a9c38fa1be0dd48efa3fac3</anchor>
+ <arglist>(const tnet_stun_attribute_t *attribute, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_t *</type>
+ <name>tnet_stun_attribute_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga9a8fea6f7fb4c6236bc4df85153d6af4</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_mapped_addr_t *</type>
+ <name>tnet_stun_attribute_mapped_address_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga28ffe32f830bbe0f5b32a207538eb8b6</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_xmapped_addr_t *</type>
+ <name>tnet_stun_attribute_xmapped_address_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gacd4af1df8c9e298a23d34df27e5dcc45</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_username_t *</type>
+ <name>tnet_stun_attribute_username_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab92c8f62b2d188c9ac1528aa03da4b7e</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_integrity_t *</type>
+ <name>tnet_stun_attribute_integrity_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3c5f79313850ea8643132b093e11ef6a</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_fingerprint_t *</type>
+ <name>tnet_stun_attribute_fingerprint_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga2432db4c4bb63da2327bb357361eef21</anchor>
+ <arglist>(uint32_t fingerprint)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_errorcode_t *</type>
+ <name>tnet_stun_attribute_errorcode_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaa51e8bc565195298fb3de24070f5614a</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_realm_t *</type>
+ <name>tnet_stun_attribute_realm_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga2d7ab50986b3af03951358ec4c2cfa8b</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_nonce_t *</type>
+ <name>tnet_stun_attribute_nonce_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga0cf404a4977b95a47c252f8101b099ce</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_unknowns_t *</type>
+ <name>tnet_stun_attribute_unknowns_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8a497b2b11b1a776ec37170ee14b6ac2</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_software_t *</type>
+ <name>tnet_stun_attribute_software_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga719d8c3ac6588124533f03f70877e437</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_altserver_t *</type>
+ <name>tnet_stun_attribute_altserver_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga586636541b8ebb9ea46d4df39a448121</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_ice_priority_t *</type>
+ <name>tnet_stun_attribute_ice_priority_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7e2992cbcf5e4d93fce285c8fdad6018</anchor>
+ <arglist>(uint32_t value)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_ice_use_candidate_t *</type>
+ <name>tnet_stun_attribute_ice_use_candidate_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gafc6efba58197cb3d697502bbad7378cf</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_ice_controlled_t *</type>
+ <name>tnet_stun_attribute_ice_controlled_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaf2e4854c90f7c8c3abae9915e59ad12f</anchor>
+ <arglist>(uint64_t value)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_attribute_ice_controlling_t *</type>
+ <name>tnet_stun_attribute_ice_controlling_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga94da0e7a21d255c8647c190387229ba3</anchor>
+ <arglist>(uint64_t value)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a1ed3e8d18968c427abbca5046e9a2aae</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_mapped_addr_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>ae158b2a2e20ebe910d5b937b6c31e8f5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_xmapped_addr_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>ade3c87fd23c4418da071a962f4fa3a18</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_username_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a3618ce3b069dc37797b7a39e60342a2e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_integrity_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a76de57dbb7322cf91c856dd8d4bba3e9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_fingerprint_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a8d8cbe79ce3fa75cad33acb8edab5b98</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_errorcode_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a81aa99bbc4ef57f453b41485a6f2aa90</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_realm_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a0327c124b1eff63f330af0b55f02c1fa</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_nonce_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a6d2b7027e8dccf917a94b53703137b8a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_unknowns_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a0db4a8abf86d2e730755456eb372f7dd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_software_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a2fcc436a3a9b8217cb57779f66ab6844</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_altserver_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a8d426ae80202c572513916de48cab014</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_ice_priority_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a2aa16d9877e44a873017f40ea3712fc6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_ice_use_candidate_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>aadbce41b24c9f38a157ca28baaf3a4c3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_ice_controlled_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a2f8cbba757f3065b192603ea5648db71</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_attribute_ice_controlling_def_t</name>
+ <anchorfile>tnet__stun__attribute_8h.html</anchorfile>
+ <anchor>a0339fb43d3cc554b59bfec0fd41d89d5</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_stun_message.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/stun/</path>
+ <filename>tnet__stun__message_8c</filename>
+ <includes id="tnet__stun__message_8h" name="tnet_stun_message.h" local="yes" imported="no">tnet_stun_message.h</includes>
+ <includes id="tnet__stun_8h" name="tnet_stun.h" local="yes" imported="no">tnet_stun.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <includes id="tnet__turn__attribute_8h" name="tnet_turn_attribute.h" local="yes" imported="no">../turn/tnet_turn_attribute.h</includes>
+ <member kind="define">
+ <type>#define</type>
+ <name>SERIALIZE_N_ADD_ATTRIBUTE</name>
+ <anchorfile>tnet__stun__message_8c.html</anchorfile>
+ <anchor>a22b95434b0e041992dd2058e5688e696</anchor>
+ <arglist>(att_name, payload, payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_message_t *</type>
+ <name>tnet_stun_message_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaaf1892e2a30f8b85e4e5b47622a6b9f3</anchor>
+ <arglist>(const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_message_t *</type>
+ <name>tnet_stun_message_create_null</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga938bc40f8bb818f87c94eb42352cd0f3</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_stun_message_serialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaefd2306ef33e3611a98394e5b274a069</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_message_t *</type>
+ <name>tnet_stun_message_deserialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga0f5f3b814bb84f3cb62802b1d9af275e</anchor>
+ <arglist>(const uint8_t *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_stun_message_has_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga250b97b6a26f99f9d545533e20d29acb</anchor>
+ <arglist>(const tnet_stun_message_t *self, tnet_stun_attribute_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_message_add_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gacb982af5ead9faf9e85b4e2f69e05d47</anchor>
+ <arglist>(tnet_stun_message_t *self, tnet_stun_attribute_t **attribute)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_message_remove_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8c3cf4006d4c030e0114b8c00f2dc5ec</anchor>
+ <arglist>(tnet_stun_message_t *self, tnet_stun_attribute_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_stun_attribute_t *</type>
+ <name>tnet_stun_message_get_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaeac2966bdc80f798ec61f6f7ebfc6a95</anchor>
+ <arglist>(const tnet_stun_message_t *self, tnet_stun_attribute_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>short</type>
+ <name>tnet_stun_message_get_errorcode</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7638d5816c344718874a113abd9739d5</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_stun_message_get_realm</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga6115407c7af73b3041c215ccd34e35b8</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_stun_message_get_nonce</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga5e068d5474bfbd73e8cece833deac6b2</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int32_t</type>
+ <name>tnet_stun_message_get_lifetime</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga12380617e5a883d3c175216c48245839</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_stun_message_transac_id_equals</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga401b2a061923a11340da833dc248fa9d</anchor>
+ <arglist>(const tnet_stun_transacid_t id1, const tnet_stun_transacid_t id2)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_stun_message_def_t</name>
+ <anchorfile>tnet__stun__message_8c.html</anchorfile>
+ <anchor>a19626e26e58ad7a9c09264174314053d</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_stun_message.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/stun/</path>
+ <filename>tnet__stun__message_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__stun__attribute_8h" name="tnet_stun_attribute.h" local="yes" imported="no">stun/tnet_stun_attribute.h</includes>
+ <class kind="struct">tnet_stun_message_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_CLASS_REQUEST_MASK</name>
+ <anchorfile>tnet__stun__message_8h.html</anchorfile>
+ <anchor>aa3d2e023082dd0468d788a204e4f5588</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_CLASS_INDICATION_MASK</name>
+ <anchorfile>tnet__stun__message_8h.html</anchorfile>
+ <anchor>a6cb86b711e3aa24320405b60f2da1beb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_CLASS_SUCCESS_MASK</name>
+ <anchorfile>tnet__stun__message_8h.html</anchorfile>
+ <anchor>a0134dd005c09929e5e557fe0d4b00ff4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_CLASS_ERROR_MASK</name>
+ <anchorfile>tnet__stun__message_8h.html</anchorfile>
+ <anchor>aa1bad5b0786da02f7562d45b83e538fc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_MESSAGE_IS_REQUEST</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga50742ed21d77367f7d6d0b1ece487d94</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_MESSAGE_IS_RESPONSE</name>
+ <anchorfile>tnet__stun__message_8h.html</anchorfile>
+ <anchor>a67a78f2b21fdd0243800c240d2453fa3</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_MESSAGE_IS_INDICATION</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga05a95d304163ba125defae8444a28f73</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_RESPONSE_IS_SUCCESS</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga98049d686a5db4369a7554a77bf26838</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_RESPONSE_IS_ERROR</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga10bdb77a5f51b4670be89302eb445974</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_IS_STUN2_MSG</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3e9c76b717211f3d8c27d624a07e2353</anchor>
+ <arglist>(PU8, SIZE)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_IS_STUN2</name>
+ <anchorfile>tnet__stun__message_8h.html</anchorfile>
+ <anchor>a308ab872ed8673719c1d0cb120b2ba03</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_TRANSACID_SIZE</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaaa796e7b0e870b335336c50024ef5823</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>uint8_t</type>
+ <name>tnet_stun_transacid_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaab3bfd494f75601a0f26177c6d851810</anchor>
+ <arglist>[TNET_STUN_TRANSACID_SIZE]</arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_stun_class_type_e</type>
+ <name>tnet_stun_class_type_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8db95f74a4953795bf182744e63eff78</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_stun_method_type_e</type>
+ <name>tnet_stun_method_type_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga145552721a7b4f524ceb40ac2da1038d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_stun_message_type_e</type>
+ <name>tnet_stun_message_type_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab3ed2f3313ef6914347c2e604d7cf104</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_message_s</type>
+ <name>tnet_stun_message_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga4e9470802bdd2d8b0a1b90631369721e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_stun_message_t</type>
+ <name>tnet_stun_response_t</name>
+ <anchorfile>tnet__stun__message_8h.html</anchorfile>
+ <anchor>ae36d2cd92b9d0f1ae545b4ba4241f35b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_stun_message_t</type>
+ <name>tnet_stun_request_t</name>
+ <anchorfile>tnet__stun__message_8h.html</anchorfile>
+ <anchor>a5f7a4c74272f8549b89d8bb2ad6206b1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_stun_class_type_e</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3faef946079e315842f5ad4d41aa0929</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_class_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3faef946079e315842f5ad4d41aa0929a4617c080243a43b3d8f93bdfcc3f0f4b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_class_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3faef946079e315842f5ad4d41aa0929a204a6136670e4ad622276ef22a2ae65e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_class_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3faef946079e315842f5ad4d41aa0929a0f27f07bfc9be6aa217799fa088cf059</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_class_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3faef946079e315842f5ad4d41aa0929a271a1bc249f8bc1af5b9e6308b166232</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_stun_method_type_e</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga4701a0e3395592a6d6a742901212801c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_binding</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801cafd301f45e6297ffca65062c30b89ef53</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_allocate</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca166402bfafe37fa33b31f1466265798b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_refresh</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca6081fbd713a271d81264c919a589ce97</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_send</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca3c8e39a747df8f52dcc70d5d7db3e423</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_data</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca72ac38a767b77800980a5577dd13059c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_createpermission</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca45791d8de7420d9d3afccfc78ac8ba8b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_channelbind</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca9a883e8885d8eb35a93beccda692233c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_stun_message_type_e</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gabf2f8d8b846fe491470941a7e237559c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_binding_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559caef49ee403fb2e849831649e4c09729d4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_binding_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca40f5bbd220cf9c1ec50654becc93c75f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_binding_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca45e30ced8713c5c159bb45641ce04e79</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_binding_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca9526f90725e2c9be01cd4ea2aa818e50</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_allocate_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cab3d8c425c241c43ab3bdbec7fdddc2dd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_allocate_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cadda6f40f23dc4bd53d1d6c068484ada0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_allocate_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559caf20455522d8e72c9e055b8ea5ef2dabb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_allocate_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cae4d21e386431edf815a9a652f3d745a5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_refresh_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca3f15b1671e604a2fb7a65401756dccc0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_refresh_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca5130e27fd810862da942fcde58eb0c42</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_refresh_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559caead4a26ba4d373a96e4dac68ff9fdb45</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_refresh_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca17067ce9dae33780b432c50b2a53130b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_send_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cac7424fdd7360f72326f8f9c74d36d15b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_data_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca66d958d23caaac30ab000f37c36a3406</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_createpermission_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca55ffb1e77c92edb303a51f7221049c66</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_createpermission_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cad1099efddc3ea3f8e91bd7953fef5c50</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_createpermission_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559caa804d83ad6928163af8e5b8c29c003dc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_createpermission_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cad3da1d3b613236f00e9747a3874eb3c8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_channelbind_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559caf9886f762e46af82fc8122ba35a95a8a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_channelbind_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cae56d07904cc9d8091f32a6973258146f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_channelbind_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cafcb4db651d71fd5c21f7bbb2def064a1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_channelbind_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cab65200966087d7dd85dd17de30cde9ab</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_buffer_t *</type>
+ <name>tnet_stun_message_serialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaefd2306ef33e3611a98394e5b274a069</anchor>
+ <arglist>(const tnet_stun_message_t *message)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_message_t *</type>
+ <name>tnet_stun_message_deserialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga0f5f3b814bb84f3cb62802b1d9af275e</anchor>
+ <arglist>(const uint8_t *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_stun_message_has_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga250b97b6a26f99f9d545533e20d29acb</anchor>
+ <arglist>(const tnet_stun_message_t *self, tnet_stun_attribute_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_stun_message_add_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gacb982af5ead9faf9e85b4e2f69e05d47</anchor>
+ <arglist>(tnet_stun_message_t *self, tnet_stun_attribute_t **attribute)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_message_remove_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8c3cf4006d4c030e0114b8c00f2dc5ec</anchor>
+ <arglist>(tnet_stun_message_t *self, tnet_stun_attribute_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_stun_attribute_t *</type>
+ <name>tnet_stun_message_get_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaeac2966bdc80f798ec61f6f7ebfc6a95</anchor>
+ <arglist>(const tnet_stun_message_t *self, tnet_stun_attribute_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>short</type>
+ <name>tnet_stun_message_get_errorcode</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7638d5816c344718874a113abd9739d5</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_stun_message_get_realm</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga6115407c7af73b3041c215ccd34e35b8</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_stun_message_get_nonce</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga5e068d5474bfbd73e8cece833deac6b2</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int32_t</type>
+ <name>tnet_stun_message_get_lifetime</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga12380617e5a883d3c175216c48245839</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_stun_message_transac_id_equals</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga401b2a061923a11340da833dc248fa9d</anchor>
+ <arglist>(const tnet_stun_transacid_t id1, const tnet_stun_transacid_t id2)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_message_t *</type>
+ <name>tnet_stun_message_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaaf1892e2a30f8b85e4e5b47622a6b9f3</anchor>
+ <arglist>(const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_message_t *</type>
+ <name>tnet_stun_message_create_null</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga938bc40f8bb818f87c94eb42352cd0f3</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_stun_message_def_t</name>
+ <anchorfile>tnet__stun__message_8h.html</anchorfile>
+ <anchor>a447a48c88e1eb9124f6ac0669a1f4000</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tinynet.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tinynet_8h</filename>
+ <includes id="tnet_8h" name="tnet.h" local="yes" imported="no">tnet.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">tnet_endianness.h</includes>
+ <includes id="tnet__nat_8h" name="tnet_nat.h" local="yes" imported="no">tnet_nat.h</includes>
+ <includes id="tnet__socket_8h" name="tnet_socket.h" local="yes" imported="no">tnet_socket.h</includes>
+ <includes id="tnet__transport_8h" name="tnet_transport.h" local="yes" imported="no">tnet_transport.h</includes>
+ <includes id="tnet__stun_8h" name="tnet_stun.h" local="yes" imported="no">stun/tnet_stun.h</includes>
+ <includes id="tnet__ice__event_8h" name="tnet_ice_event.h" local="yes" imported="no">ice/tnet_ice_event.h</includes>
+ <includes id="tnet__ice__candidate_8h" name="tnet_ice_candidate.h" local="yes" imported="no">ice/tnet_ice_candidate.h</includes>
+ <includes id="tnet__ice__ctx_8h" name="tnet_ice_ctx.h" local="yes" imported="no">ice/tnet_ice_ctx.h</includes>
+ <includes id="tnet__dns_8h" name="tnet_dns.h" local="yes" imported="no">dns/tnet_dns.h</includes>
+ <includes id="tnet__dns__naptr_8h" name="tnet_dns_naptr.h" local="yes" imported="no">dns/tnet_dns_naptr.h</includes>
+ <includes id="tnet__dns__regexp_8h" name="tnet_dns_regexp.h" local="yes" imported="no">dns/tnet_dns_regexp.h</includes>
+ <includes id="tnet__dns__resolvconf_8h" name="tnet_dns_resolvconf.h" local="yes" imported="no">dns/tnet_dns_resolvconf.h</includes>
+ <includes id="tnet__dhcp_8h" name="tnet_dhcp.h" local="yes" imported="no">dhcp/tnet_dhcp.h</includes>
+ <includes id="tnet__dhcp__option__sip_8h" name="tnet_dhcp_option_sip.h" local="yes" imported="no">dhcp/tnet_dhcp_option_sip.h</includes>
+ <includes id="tnet__dhcp6_8h" name="tnet_dhcp6.h" local="yes" imported="no">dhcp6/tnet_dhcp6.h</includes>
+ <includes id="tnet__dhcp6__option_8h" name="tnet_dhcp6_option.h" local="yes" imported="no">dhcp6/tnet_dhcp6_option.h</includes>
+ </compound>
+ <compound kind="file">
+ <name>tinynet_config.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tinynet__config_8h</filename>
+ <member kind="define">
+ <type>#define</type>
+ <name>TINYNET_API</name>
+ <anchorfile>tinynet__config_8h.html</anchorfile>
+ <anchor>aae93e76d17d1ca6ff95aad28b3abf658</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TINYNET_GEXTERN</name>
+ <anchorfile>tinynet__config_8h.html</anchorfile>
+ <anchor>a81d479293190a58ef229b695fb4a8ab0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_BEGIN_DECLS</name>
+ <anchorfile>tinynet__config_8h.html</anchorfile>
+ <anchor>a75bf1f5d1f1371c87bf2f5d9d61f458b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_END_DECLS</name>
+ <anchorfile>tinynet__config_8h.html</anchorfile>
+ <anchor>a48c3cca1fa120fe82738d64e85c34351</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_INLINE</name>
+ <anchorfile>tinynet__config_8h.html</anchorfile>
+ <anchor>a6e01306b61ca63a7ff08571c01bcd5e2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOFTWARE</name>
+ <anchorfile>tinynet__config_8h.html</anchorfile>
+ <anchor>ae2d04c0df9b8a96c09fde862ec6e4304</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_IANA_PEN</name>
+ <anchorfile>tinynet__config_8h.html</anchorfile>
+ <anchor>a612c5d1310d848ba03078217088c3d26</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_RESOLV_CONF_PATH</name>
+ <anchorfile>tinynet__config_8h.html</anchorfile>
+ <anchor>ab55f5a2cc9ce6e6b281afa7f869956f5</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dtls.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/tls/</path>
+ <filename>tnet__dtls_8c</filename>
+ <includes id="tnet__dtls_8h" name="tnet_dtls.h" local="yes" imported="no">tnet_dtls.h</includes>
+ <includes id="tnet__tls_8h" name="tnet_tls.h" local="yes" imported="no">tnet_tls.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <class kind="struct">tnet_dtls_socket_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>_tnet_dtls_socket_do_handshake</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>ace7d8b69e95ad5631aa022097c832d8a</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>_tnet_dtls_socket_raise_event</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>afd9fe6841791319d91514235cb7a3395</anchor>
+ <arglist>(self, type, data, size)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>_tnet_dtls_socket_raise_event_dataless</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a63e098461c2ff5c68fe8dea627634ce1</anchor>
+ <arglist>(self, type)</arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dtls_socket_s</type>
+ <name>tnet_dtls_socket_t</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a24f671f502be206e1120cdff7a6a50a9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_dtls_is_srtp_supported</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>ad09a2debbb13fe5c0cc698a61df65dc7</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_dtls_is_supported</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a25238311d78e2aca33c0d6c215896bae</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dtls_hash_type_t</type>
+ <name>tnet_dtls_get_hash_from_string</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>aadd696d262808b42f37a1a2030d815c3</anchor>
+ <arglist>(const char *hash)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dtls_setup_t</type>
+ <name>tnet_dtls_get_setup_from_string</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a40fb953e7deaaf95bd89ca1c1099a928</anchor>
+ <arglist>(const char *setup)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dtls_get_fingerprint</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>afb717cd09e0f914acefc0a62f6ee68df</anchor>
+ <arglist>(const char *certfile, tnet_fingerprint_t *fingerprint, tnet_dtls_hash_type_t hash)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dtls_socket_handle_t *</type>
+ <name>tnet_dtls_socket_create</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a44afb468495ae1cec8aea9457dc392d1</anchor>
+ <arglist>(tnet_fd_t fd, struct ssl_ctx_st *ssl_ctx)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_fd_t</type>
+ <name>tnet_dtls_socket_get_fd</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a16d3cdc446403a2aef45e3fb2d1cde40</anchor>
+ <arglist>(const tnet_dtls_socket_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>struct sockaddr_storage *</type>
+ <name>tnet_dtls_socket_get_remote_addr</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a8f9c9ffba8efe2f3acf1fbcb9f5eca87</anchor>
+ <arglist>(const tnet_dtls_socket_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dtls_socket_set_callback</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a99f946ceca66bc754ef1e0b0d5e4dc39</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle, const void *usrdata, tnet_dtls_socket_cb_f func)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dtls_socket_set_remote_fingerprint</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a39f580983e0ad861df949c142ca785a2</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle, const tnet_fingerprint_t *fingerprint, tnet_dtls_hash_type_t hash)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dtls_socket_use_srtp</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a50ad734fe046869215f1651013054d37</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dtls_socket_set_setup</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>acaee108ca648f7c328c355081bfb70dc</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle, tnet_dtls_setup_t setup)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_dtls_socket_is_remote_cert_fp_match</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>aa244e20933fc3301323cc3c28918964e</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dtls_socket_do_handshake</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a73d03cb325831285b68fd7c291fe2efc</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle, const struct sockaddr_storage *remote_addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_dtls_socket_is_handshake_completed</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a208edc774b7e0000f82a51144222a041</anchor>
+ <arglist>(const tnet_dtls_socket_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dtls_socket_handle_incoming_data</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>af48bb9403a9bac2421f5914a20c36cff</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle, const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_dtls_socket_def_t</name>
+ <anchorfile>tnet__dtls_8c.html</anchorfile>
+ <anchor>a91eab3d9db44ae1e119a3d7c174e505c</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_dtls.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/tls/</path>
+ <filename>tnet__dtls_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <member kind="typedef">
+ <type>void</type>
+ <name>tnet_dtls_socket_handle_t</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a31d0de4ae3dd651cffe744aa94d36f27</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dtls_socket_event_type_e</type>
+ <name>tnet_dtls_socket_event_type_t</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>aa4e6c5e99dc54e204378391e54ad14d4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>int(*</type>
+ <name>tnet_dtls_socket_cb_f</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a3529a64ddc3fa5f07ed3c692bebc560a</anchor>
+ <arglist>)(const void *usrdata, tnet_dtls_socket_event_type_t e, const tnet_dtls_socket_handle_t *handle, const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dtls_socket_event_type_e</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a5161f0204780718c0b573c7970d4a0de</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_socket_event_type_handshake_started</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a5161f0204780718c0b573c7970d4a0dea43948921572953c4e898af4cf1c22702</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_socket_event_type_handshake_succeed</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a5161f0204780718c0b573c7970d4a0deafb14934d988f7708669f370b537a7def</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_socket_event_type_handshake_failed</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a5161f0204780718c0b573c7970d4a0dea114444f752950d9f75fcfcf74d1c51bc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_socket_event_type_fingerprint_mismatch</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a5161f0204780718c0b573c7970d4a0deadfc3a56addce201f9e50bdd655081828</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_socket_event_type_error</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a5161f0204780718c0b573c7970d4a0deaed3d12a2bc8ab5c18c15e3a92ec749c6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_socket_event_type_dtls_srtp_profile_selected</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a5161f0204780718c0b573c7970d4a0dea7dd0a2996205b1a37530f288f48a1089</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_socket_event_type_dtls_srtp_data</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a5161f0204780718c0b573c7970d4a0dea975c7bcd42f5cfd82262b79b0864ace2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_dtls_is_srtp_supported</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a43e4fc390be71148720b2a191702ef8a</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_dtls_is_supported</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>ac6f9f9b863ff1105fbb27cfb37f9b53a</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dtls_hash_type_t</type>
+ <name>tnet_dtls_get_hash_from_string</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>ac8028156e7807585a4c621821ca93564</anchor>
+ <arglist>(const char *hash)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dtls_setup_t</type>
+ <name>tnet_dtls_get_setup_from_string</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a1e8ae82dce1152a51863aa93ccf5a1c1</anchor>
+ <arglist>(const char *setup)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dtls_get_fingerprint</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a624c230b834e6b4f6cc82bd4affd4b13</anchor>
+ <arglist>(const char *certfile, tnet_fingerprint_t *fingerprint, tnet_dtls_hash_type_t hash)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_dtls_socket_handle_t *</type>
+ <name>tnet_dtls_socket_create</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>ad22dbfe69ef4b9aebe1a58ba6ac28df9</anchor>
+ <arglist>(tnet_fd_t fd, struct ssl_ctx_st *ssl_ctx)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_fd_t</type>
+ <name>tnet_dtls_socket_get_fd</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>ad86275a4b6a016bb8abdff853d468aa5</anchor>
+ <arglist>(const tnet_dtls_socket_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API struct sockaddr_storage *</type>
+ <name>tnet_dtls_socket_get_remote_addr</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a4904903b026ee11936300d9ab68ff6a5</anchor>
+ <arglist>(const tnet_dtls_socket_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dtls_socket_set_callback</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a20024a2fa68ba9bd25c931dfa7a57dab</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle, const void *usrdata, tnet_dtls_socket_cb_f func)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dtls_socket_set_remote_fingerprint</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a3cc5666b7c805601e87b39efc6e54c47</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle, const tnet_fingerprint_t *fingerprint, tnet_dtls_hash_type_t hash)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dtls_socket_use_srtp</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a3345ecf76fd86aeee8849291f8acde0f</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dtls_socket_set_setup</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a4392b4e116b50e93986b71412f5745aa</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle, tnet_dtls_setup_t setup)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_dtls_socket_is_remote_cert_fp_match</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a1d12a561c9bfadae2047d57f1f7069c0</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dtls_socket_do_handshake</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a396d2828d6a41bf9aa8b015234378913</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle, const struct sockaddr_storage *remote_addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_dtls_socket_is_handshake_completed</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a2c482e33bedc851800e9c52b257c4b73</anchor>
+ <arglist>(const tnet_dtls_socket_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_dtls_socket_handle_incoming_data</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>afb18054bdb7bff7c36c8ed83bd705e51</anchor>
+ <arglist>(tnet_dtls_socket_handle_t *handle, const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_dtls_socket_def_t</name>
+ <anchorfile>tnet__dtls_8h.html</anchorfile>
+ <anchor>a935d64508e3f73649a7ccdbec9dcbf91</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_tls.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/tls/</path>
+ <filename>tnet__tls_8c</filename>
+ <includes id="tnet__tls_8h" name="tnet_tls.h" local="yes" imported="no">tnet_tls.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <class kind="struct">tnet_tls_socket_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TLS_TIMEOUT</name>
+ <anchorfile>tnet__tls_8c.html</anchorfile>
+ <anchor>a8a5893e48b2a03cdf2ad2fdf4dab27fb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TLS_RETRY_COUNT</name>
+ <anchorfile>tnet__tls_8c.html</anchorfile>
+ <anchor>acf3b352408903e8954c01cdc9999d0ee</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_tls_socket_s</type>
+ <name>tnet_tls_socket_t</name>
+ <anchorfile>tnet__tls_8c.html</anchorfile>
+ <anchor>ab3bf41a1258ce44672ff13f23a2ecf17</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_tls_is_supported</name>
+ <anchorfile>tnet__tls_8c.html</anchorfile>
+ <anchor>ad04214197a9e36d79b813a2c13de54e3</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_tls_socket_handle_t *</type>
+ <name>tnet_tls_socket_create</name>
+ <anchorfile>tnet__tls_8c.html</anchorfile>
+ <anchor>ac6938704c21f0790191b153e3e9ac593</anchor>
+ <arglist>(tnet_fd_t fd, struct ssl_ctx_st *ssl_ctx)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_tls_socket_connect</name>
+ <anchorfile>tnet__tls_8c.html</anchorfile>
+ <anchor>a188bd068a96c3acc2f031cb6d04d4458</anchor>
+ <arglist>(tnet_tls_socket_handle_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_tls_socket_accept</name>
+ <anchorfile>tnet__tls_8c.html</anchorfile>
+ <anchor>a2bf506e70d5eb1b45ee6a9f8b5a6d690</anchor>
+ <arglist>(tnet_tls_socket_handle_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_tls_socket_write</name>
+ <anchorfile>tnet__tls_8c.html</anchorfile>
+ <anchor>a43612982a13f6f14301034c5ce1b7cb7</anchor>
+ <arglist>(tnet_tls_socket_handle_t *self, const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_tls_socket_recv</name>
+ <anchorfile>tnet__tls_8c.html</anchorfile>
+ <anchor>a989798393b8e30bc55f3904c0324da6f</anchor>
+ <arglist>(tnet_tls_socket_handle_t *self, void **data, tsk_size_t *size, tsk_bool_t *isEncrypted)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_tls_socket_def_t</name>
+ <anchorfile>tnet__tls_8c.html</anchorfile>
+ <anchor>a4e4baa33e452176cd4a4a52ca5148bcf</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_tls.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/tls/</path>
+ <filename>tnet__tls_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_tls_socket_send</name>
+ <anchorfile>tnet__tls_8h.html</anchorfile>
+ <anchor>ae8efefb3d96440fe53fc8a4572613c5e</anchor>
+ <arglist>(self, data, size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_tls_socket_connect</name>
+ <anchorfile>tnet__tls_8h.html</anchorfile>
+ <anchor>a188bd068a96c3acc2f031cb6d04d4458</anchor>
+ <arglist>(tnet_tls_socket_handle_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_tls_socket_accept</name>
+ <anchorfile>tnet__tls_8h.html</anchorfile>
+ <anchor>a2bf506e70d5eb1b45ee6a9f8b5a6d690</anchor>
+ <arglist>(tnet_tls_socket_handle_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_tls_socket_write</name>
+ <anchorfile>tnet__tls_8h.html</anchorfile>
+ <anchor>a43612982a13f6f14301034c5ce1b7cb7</anchor>
+ <arglist>(tnet_tls_socket_handle_t *self, const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_tls_socket_recv</name>
+ <anchorfile>tnet__tls_8h.html</anchorfile>
+ <anchor>a989798393b8e30bc55f3904c0324da6f</anchor>
+ <arglist>(tnet_tls_socket_handle_t *self, void **data, tsk_size_t *size, tsk_bool_t *isEncrypted)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_tls_is_supported</name>
+ <anchorfile>tnet__tls_8h.html</anchorfile>
+ <anchor>a8adca95fbe88dc5bd5ab67632055bf6e</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_tls_socket_handle_t *</type>
+ <name>tnet_tls_socket_create</name>
+ <anchorfile>tnet__tls_8h.html</anchorfile>
+ <anchor>ae406f12f84152b4c6f735e6ae8b4df7d</anchor>
+ <arglist>(tnet_fd_t fd, struct ssl_ctx_st *ssl_ctx)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TNET_BEGIN_DECLS typedef void</type>
+ <name>tnet_tls_socket_handle_t</name>
+ <anchorfile>tnet__tls_8h.html</anchorfile>
+ <anchor>a6f1311b1d1c8744b36092ebcbf1a3b87</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_tls_socket_def_t</name>
+ <anchorfile>tnet__tls_8h.html</anchorfile>
+ <anchor>a8ed545d5b0d5aad6da18b942e2b53e1a</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet_8c</filename>
+ <includes id="tnet_8h" name="tnet.h" local="yes" imported="no">tnet.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_startup</name>
+ <anchorfile>tnet_8c.html</anchorfile>
+ <anchor>ae58106beb601241b29d944fe40c8f300</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_cleanup</name>
+ <anchorfile>tnet_8c.html</anchorfile>
+ <anchor>ac42b22a7ac5831f04326aee9de033c84</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>tnet_isBigEndian</name>
+ <anchorfile>tnet_8c.html</anchorfile>
+ <anchor>acd8f51d06c3a3d408e2b52428034cc24</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <member kind="function">
+ <type>TNET_BEGIN_DECLS TINYNET_API int</type>
+ <name>tnet_startup</name>
+ <anchorfile>tnet_8h.html</anchorfile>
+ <anchor>a4ed9dafe102a2a8e0789f0c901206963</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_cleanup</name>
+ <anchorfile>tnet_8h.html</anchorfile>
+ <anchor>a3347306376677277d94b22ea3770cac6</anchor>
+ <arglist>()</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_auth.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__auth_8c</filename>
+ <includes id="tnet__auth_8h" name="tnet_auth.h" local="yes" imported="no">tnet_auth.h</includes>
+ </compound>
+ <compound kind="file">
+ <name>tnet_auth.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__auth_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ </compound>
+ <compound kind="file">
+ <name>tnet_endianness.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__endianness_8c</filename>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">tnet_endianness.h</includes>
+ <includes id="tnet_8h" name="tnet.h" local="yes" imported="no">tnet.h</includes>
+ <member kind="function">
+ <type>unsigned short</type>
+ <name>tnet_htons</name>
+ <anchorfile>tnet__endianness_8c.html</anchorfile>
+ <anchor>a81f024d1f14e062410246f86802d12b3</anchor>
+ <arglist>(unsigned short x)</arglist>
+ </member>
+ <member kind="function">
+ <type>unsigned short</type>
+ <name>tnet_htons_2</name>
+ <anchorfile>tnet__endianness_8c.html</anchorfile>
+ <anchor>a275f5dd051fd16045c4e893c32bac06c</anchor>
+ <arglist>(const void *px)</arglist>
+ </member>
+ <member kind="function">
+ <type>unsigned long</type>
+ <name>tnet_htonl</name>
+ <anchorfile>tnet__endianness_8c.html</anchorfile>
+ <anchor>a9c62f72b9d9f37546da167712dd3d706</anchor>
+ <arglist>(unsigned long x)</arglist>
+ </member>
+ <member kind="function">
+ <type>unsigned long</type>
+ <name>tnet_htonl_2</name>
+ <anchorfile>tnet__endianness_8c.html</anchorfile>
+ <anchor>a8f8cd820e624e51cce6a5c4f801a6f46</anchor>
+ <arglist>(const void *px)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_is_BE</name>
+ <anchorfile>tnet__endianness_8c.html</anchorfile>
+ <anchor>a8e88a1ef1bc84108223787779f504a41</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>tnet_isBigEndian</name>
+ <anchorfile>tnet__endianness_8c.html</anchorfile>
+ <anchor>acd8f51d06c3a3d408e2b52428034cc24</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_endianness.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__endianness_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_ntohs</name>
+ <anchorfile>tnet__endianness_8h.html</anchorfile>
+ <anchor>a173b0ead154f408f9431cb89f167db7d</anchor>
+ <arglist>(x)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_ntohs_2</name>
+ <anchorfile>tnet__endianness_8h.html</anchorfile>
+ <anchor>a75320a16b5817e68c17bb33f4e10c811</anchor>
+ <arglist>(px)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_ntohl</name>
+ <anchorfile>tnet__endianness_8h.html</anchorfile>
+ <anchor>a3421e42a8d227dfd846bccb37f0dc490</anchor>
+ <arglist>(x)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_ntohl_2</name>
+ <anchorfile>tnet__endianness_8h.html</anchorfile>
+ <anchor>ae1122c736d013aa5cd562e6b9f2a2096</anchor>
+ <arglist>(px)</arglist>
+ </member>
+ <member kind="function">
+ <type>TNET_BEGIN_DECLS TINYNET_API TNET_INLINE unsigned short</type>
+ <name>tnet_htons</name>
+ <anchorfile>tnet__endianness_8h.html</anchorfile>
+ <anchor>a9128b3b5b1eb078b0ae063c279cf6614</anchor>
+ <arglist>(unsigned short x)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API TNET_INLINE unsigned short</type>
+ <name>tnet_htons_2</name>
+ <anchorfile>tnet__endianness_8h.html</anchorfile>
+ <anchor>a76d99c559f54d176c76e1d0b7cec11d1</anchor>
+ <arglist>(const void *px)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API TNET_INLINE unsigned long</type>
+ <name>tnet_htonl</name>
+ <anchorfile>tnet__endianness_8h.html</anchorfile>
+ <anchor>ae3b9343ade3115c02db59eaacf9c07a3</anchor>
+ <arglist>(unsigned long x)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API TNET_INLINE unsigned long</type>
+ <name>tnet_htonl_2</name>
+ <anchorfile>tnet__endianness_8h.html</anchorfile>
+ <anchor>aaa4d43dde222ab2d0b7191b071073f2c</anchor>
+ <arglist>(const void *px)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API TNET_INLINE tsk_bool_t</type>
+ <name>tnet_is_BE</name>
+ <anchorfile>tnet__endianness_8h.html</anchorfile>
+ <anchor>a1c7a87c0f35e81028d0f636b398e43d9</anchor>
+ <arglist>()</arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_hardwares.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__hardwares_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS enum tnet_hardware_type_e</type>
+ <name>tnet_hardware_type_t</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>ab3965c39fd276c764c0e59d2a1bb010a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_hardware_type_e</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_Ethernet_10Mb</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cbab973f191210bbc4e5c4c2fe741d81b78</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_Ethernet_3Mb</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cbac897b3c01ee006b71c41fba02c145056</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_AX_25</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba6886c8486caa3f75207f3a1c17b6fa24</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_Token_Ring</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba2f09deb1fad80172d241c4abbddc81cb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_Chaos</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba6bada0b3a49c4d4eb9407ade58dc340e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_IEEE_802_Networks</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba30df3e42f825f3ea51d8f6dbdf015649</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_ARCNET</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba6fe010a6818866fa788b3a77d559c61a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_Hyperchannel</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba1e8e9de9afe46777392cd2df3770bdc3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_Lanstar</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cbae739a32782957a1d35cac1fe0baae7ae</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_Autonet_Short_Address</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba9112021ec25e617eadbb93a764765563</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_ALocalTalk</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba4cd5f244ef725671f9dff6bedf451765</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_LocalNet</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba37870cb45352e7de380499f0b4b42c22</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_Ultra_link</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba0940480918527435321bdd93a46557a0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_SMDS</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba73dc9b1bdd675ecf6f3933383fa8d551</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_Frame_Relay</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cba4acacd1d8fadbdb927193083052d5e0a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_htype_ATM</name>
+ <anchorfile>tnet__hardwares_8h.html</anchorfile>
+ <anchor>a9707b4f020ac44c0ccd61ec6636a91cbaaca0d9ed7748a27d0f4dd7c05b9b28e8</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_nat.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__nat_8c</filename>
+ <includes id="tnet__nat_8h" name="tnet_nat.h" local="yes" imported="no">tnet_nat.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_nat_context_handle_t *</type>
+ <name>tnet_nat_context_create</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga49c2521bd48d6df2ce3a46e066ebe874</anchor>
+ <arglist>(tnet_socket_type_t socket_type, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>__pred_find_turn_allocation</name>
+ <anchorfile>tnet__nat_8c.html</anchorfile>
+ <anchor>ace6d31bc9dea175a5262eac6fcff6780</anchor>
+ <arglist>(const tsk_list_item_t *item, const void *id)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>__pred_find_stun_binding</name>
+ <anchorfile>tnet__nat_8c.html</anchorfile>
+ <anchor>a8c276667804d2cf335a29d74008a46e2</anchor>
+ <arglist>(const tsk_list_item_t *item, const void *id)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>__pred_find_turn_channel_binding</name>
+ <anchorfile>tnet__nat_8c.html</anchorfile>
+ <anchor>ae3753168b39e7bc9f746ba229c7d277e</anchor>
+ <arglist>(const tsk_list_item_t *item, const void *id)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_address_tostring</name>
+ <anchorfile>tnet__nat_8c.html</anchorfile>
+ <anchor>aae3c07155263489e90e7575060571a28</anchor>
+ <arglist>(const uint8_t in_ip[16], tnet_stun_addr_family_t family, char **out_ip)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_set_server_address</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga60f64045a1a894a41afdb73a332f8732</anchor>
+ <arglist>(tnet_nat_context_handle_t *self, const char *server_address)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_set_server</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gadb5209238b5596dac88606e5130dc93f</anchor>
+ <arglist>(tnet_nat_context_handle_t *self, const char *server_address, tnet_port_t server_port)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_binding_id_t</type>
+ <name>tnet_nat_stun_bind</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gaedaee292e59564e952b1ddda3b82f0a6</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, const tnet_fd_t localFD)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_stun_get_reflexive_address</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga806a269daee5625262abe17c730d6bfc</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_stun_binding_id_t id, char **ipaddress, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_stun_unbind</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gac7501503711b402a1863967000970e16</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_stun_binding_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_allocation_id_t</type>
+ <name>tnet_nat_turn_allocate</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga0388eae3c1cb2390070e49845a9e7a33</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, const tnet_fd_t localFD)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_get_reflexive_address</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga4417d9c60fcfae071ffee563b1e5f4dd</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id, char **ipaddress, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_allocation_refresh</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga6c0eb272fdaf34b696f40aa7f5279c24</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_unallocate</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga5ffc9393817f43bdd1331454a6f8af6e</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_channel_binding_id_t</type>
+ <name>tnet_nat_turn_channel_bind</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga2c1bed31feafaa25d30cf8cc92b0b9e5</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id, struct sockaddr_storage *peer)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_channel_refresh</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga4995c26dc8e520f2820924082b1c5193</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_channel_binding_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_channel_send</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga69719fb972fa3ccf667dd3999c221e8c</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_channel_binding_id_t id, const void *data, tsk_size_t size, int indication)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_add_permission</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga67181e6f65d829d44089841fd72429f0</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id, const char *ipaddress, uint32_t timeout)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_nat_context_def_t</name>
+ <anchorfile>tnet__nat_8c.html</anchorfile>
+ <anchor>a9129d9b49b76e3c71058b17443d1fd21</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_nat.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__nat_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__stun_8h" name="tnet_stun.h" local="yes" imported="no">stun/tnet_stun.h</includes>
+ <includes id="tnet__turn_8h" name="tnet_turn.h" local="yes" imported="no">turn/tnet_turn.h</includes>
+ <includes id="tnet__proto_8h" name="tnet_proto.h" local="yes" imported="no">tnet_proto.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <class kind="struct">tnet_nat_context_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_NAT_DEFAULT_RTO</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga18cf72a341f3c785ab00a746286db1e6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_NAT_DEFAULT_RC</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga5e809d1461c049e1830e5d376a07bd11</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_NAT_TCP_UDP_DEFAULT_PORT</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga0a871f1c40c7acb827f0513958ec8b21</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_nat_turn_channel_sendindication</name>
+ <anchorfile>tnet__nat_8h.html</anchorfile>
+ <anchor>a90eee7a015088fda4281cb913d998f6f</anchor>
+ <arglist>(context, channel_id, data, size)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_nat_turn_channel_senddata</name>
+ <anchorfile>tnet__nat_8h.html</anchorfile>
+ <anchor>a66bbb47e80ab5c9ba3252d2dae1dbc06</anchor>
+ <arglist>(context, channel_id, data, size)</arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_nat_context_s</type>
+ <name>tnet_nat_context_t</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga4d037b7a4416b7e876163d3c05256a1e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>void</type>
+ <name>tnet_nat_context_handle_t</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga82ef754b59414ada0129fa558e9f3ec2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_nat_set_server_address</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga60f64045a1a894a41afdb73a332f8732</anchor>
+ <arglist>(tnet_nat_context_handle_t *self, const char *server_address)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_nat_set_server</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gadb5209238b5596dac88606e5130dc93f</anchor>
+ <arglist>(tnet_nat_context_handle_t *self, const char *server_address, tnet_port_t server_port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_stun_binding_id_t</type>
+ <name>tnet_nat_stun_bind</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gaedaee292e59564e952b1ddda3b82f0a6</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, const tnet_fd_t localFD)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_nat_stun_get_reflexive_address</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga806a269daee5625262abe17c730d6bfc</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_stun_binding_id_t id, char **ipaddress, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_nat_stun_unbind</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gac7501503711b402a1863967000970e16</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_stun_binding_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_turn_allocation_id_t</type>
+ <name>tnet_nat_turn_allocate</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga0388eae3c1cb2390070e49845a9e7a33</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, const tnet_fd_t localFD)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_nat_turn_get_reflexive_address</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga4417d9c60fcfae071ffee563b1e5f4dd</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id, char **ipaddress, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_nat_turn_allocation_refresh</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga6c0eb272fdaf34b696f40aa7f5279c24</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_nat_turn_unallocate</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga5ffc9393817f43bdd1331454a6f8af6e</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_turn_channel_binding_id_t</type>
+ <name>tnet_nat_turn_channel_bind</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga2c1bed31feafaa25d30cf8cc92b0b9e5</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id, struct sockaddr_storage *peer)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_nat_turn_channel_refresh</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga4995c26dc8e520f2820924082b1c5193</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_channel_binding_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_nat_turn_channel_send</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga69719fb972fa3ccf667dd3999c221e8c</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_channel_binding_id_t id, const void *data, tsk_size_t size, int indication)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_nat_turn_add_permission</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga67181e6f65d829d44089841fd72429f0</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id, const char *ipaddress, uint32_t timeout)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_nat_context_handle_t *</type>
+ <name>tnet_nat_context_create</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga49c2521bd48d6df2ce3a46e066ebe874</anchor>
+ <arglist>(tnet_socket_type_t socket_type, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_nat_context_def_t</name>
+ <anchorfile>tnet__nat_8h.html</anchorfile>
+ <anchor>a6efcbbf185da7cd50b10cc78f223e46a</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_poll.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__poll_8c</filename>
+ <includes id="tnet__poll_8h" name="tnet_poll.h" local="yes" imported="no">tnet_poll.h</includes>
+ </compound>
+ <compound kind="file">
+ <name>tnet_poll.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__poll_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ </compound>
+ <compound kind="file">
+ <name>tnet_proto.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__proto_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <member kind="typedef">
+ <type>enum tnet_proto_e</type>
+ <name>tnet_proto_t</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a27bb5837a79968f327ad1a267a8c889c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_proto_e</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133ae</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_HOPOPT</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaf3e47a1629582de15246a7167a0bdd16</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ICMP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaf865505c8426585ea585708127320a83</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IGMP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea26433dfcf3cded8b37cf14e85cc3f7ab</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_GGP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaace31a772721b89e781980decbd241df</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeae52d5e72b84fb84fa5eaa10540d793d5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ST</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeabb3aad067064efaca8edfafca3dc5313</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_TCP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea9435391a4b92958ff1b572fda6e5de06</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_CBT</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea50c34cc36ebac6575280c91a53f55e56</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_EGP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeacaba03f5ed57c57010aa4f7ce160e028</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IGP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaefec4433c2ebe190a48a58eb86370522</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_BBN_RCC_MON</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea4e9f8d8e68b675dccc06b04d6d5dd6f8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_NVP_II</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaa3c0b656773e9e04e8bc86dcdd1420a6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_PUP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea4fb43aa371a2864f156e4cce1b6e388f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ARGUS</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea4f8301edc15722f5262a086bf98184ea</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_EMCON</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea39ab7c2ef09951ca1c1f0c3c67524f3c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_XNET</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea054eba5ab5a811bbd20049468a61ec9c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_CHAOS</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeabda0e6c71bb52cb79a58b9d158ed4f5e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_UDP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeab30520cf1f872f6295ad002ebbdeada2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_MUX</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaaa50ec2e5cb8efcae5d4280e852f440e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_DCN_MEAS</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeabd9ac558d333c6f5e100980dd61a4f1c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_HMP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea04aa90429252022197d71301737d9e91</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_PRM</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aead370323784a60ce792f6302ec283b3e1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_XNS_IDP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea6395e15ee84f3267e20862601af11c44</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_TRUNK_1</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea20a62b2324ba93e34219549ccf6616cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_TRUNK_2</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaee772df2109724660e22843029a78001</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_LEAF_1</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaba4591261fca995da12939a87dca2f8d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_LEAF_2</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeab46c29f0e2e062d3fe07daf39273bd34</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_RDP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea517b71e70817cc73e07779730b2f7165</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IRTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeae13acc04aa32d48d6d5e223e8850b2ec</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ISO_TP4</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea93464153b54e36073d5800322ec2f0a1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_NETBLT</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea17bc22f36029bd02a60768c4d617f017</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_MFE_NSP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea012f95544ab4b0e9abb0aab5727ec85e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_MERIT_INP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea70b4c6a63c4f2e5165df28537a87e35a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_DCCP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaa833da1668e07e6cd23c58e5a4453cb8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_3PC</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea64cfc68e827206b5aa16a2044a635ef6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IDPR</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea0f404ea94e7869b1c291cf691a5142ee</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_XTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea77985b0994cdd86feb7f237229ec2510</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_DDP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea51f5684c0ecd0df92cea76008334042b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IDPR_CMTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea8b5687e2751a055d7bb1211c35a41f16</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_TP_PP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea47843d626abcb8aa8d8ae64b2a85eb2b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IL</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea9693931b5c7c19c1a4a9536b6cd0c927</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPv6</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea1e3279cb942513c78e96d07611e1c807</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SDRP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea15392913ac5f2dd4449991c9979d7dfd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPv6_Route</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaf61f8f71a9115ac879452ba0882d1233</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPv6_Frag</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaa1d78d263cd7197a91160b15bb6a26b2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IDRP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea1400b8a16f2ac5e35aa201a1deeaf35f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_RSVP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea93fc82a4b0f05472fdf72bcbb3a78039</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_GRE</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeab02932b56775158f9defaebbb6d67cdc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_DSR</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea81a55e871f9b9eae24cbc113b2f97494</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_BNA</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeab394f5c29aa46f830e2183589ffe5099</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ESP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea29a02ced688139bff0bef253bb461ee1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_AH</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea9059e24e96769fcf1a382d8abe3d256e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_I_NLSP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea0c94154394b65fd6d5d3038e5936700e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SWIPE</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea570fafde2ba504c828e5e1ea29fc0e29</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_NARP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea8bf22c4615143141a45f59c76b1f47ff</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_MOBILE</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaf0ccd8ed530ff2ff6d4d71cf5d317565</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_TLSP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea8fb5426051f59e24b779b3fc7698ddf0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SKIP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea225f1051b106ed58e22addff8d499376</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPv6_ICMP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea62eff837f8816a052c697ab4e41ecc97</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPv6_NoNxt</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea6085956fd26c4a20ce79363979848d8a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPv6_Opts</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea95b1f2a54b04b3a179772ba3130db77e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ANY_INTERNAL</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea2859d72882404810011b78d7012e061b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_CFTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea00950076d09f14d08d0f0858c26361e0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ANY_LOCAL</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaaed167548d4677aff1c8597b2fe38355</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SAT_EXPAK</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea29981fe207506ea4d111ccc2cd1b706b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_KRYPTOLAN</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea55b992f416f6568a7491c2dc92003a02</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_RVD</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaf7b535cc4f183a300ef3585fd0c7709a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPPC</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea7f5a3ca6ee5590c96204b3c760e0aab7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ANY_DISTRIBUTED</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeac335cdea345a239d64afc7ea15df455b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SAT_MON</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeadfa9bdbf063ec12290969b909bbbae7d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_VISA</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeadc121b25976e2b89f687eeaaa7198926</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPCV</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea7ca1714ed0a1befdea1322004750834a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_CPNX</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea21702fc04028001091718e7ec3f68049</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_CPHB</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aead30a6979e388107238e864df64d5fa52</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_WSN</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeacfa6a2dcb25628b1eb837db3f198384c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_PVP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeae3a08bedc4bfc8504f9b6c69c16640de</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_BR_SAT_MON</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aead4217c62a62f2db7ba92b397c090083e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SUN_ND</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea0906af73c851e2328283a7bb7cf2db51</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_WB_MON</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea2f96458c8c0785a44c3755a2eb38a24a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_WB_EXPAK</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea18d3794110ef7a0d3a2872c32170bac3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ISO_IP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea896824b5ad131da8acb7524b4d3f1e00</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_VMTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea89f9c06f2e5b1a8e27e2df1f3c678e9f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SECURE_VMTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea047328a5839ab985585203106f27a555</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_VINES</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea020bc53b165ce3d2fbf6ed68d5f7de16</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_TTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea545a0d51c04bde9d068d6bc847af2446</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_NSFNET_IGP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea3159d9719df7c3c1957cd41318ad3364</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_DGP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaac8dd71e6b5d9ecaaf6e3d4cfcd2bded</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_TCF</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaad09c0dc637474467e948e826b3491c8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_EIGRP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea5c35e9e935b96097e9509b307b7c90c6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_OSPFIGP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea01586d5552d8819526e76c9e8432e7bd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_Sprite_RPC</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeae3294f17f28d481cb31855f51e1ec5ce</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_LARP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea258f4746d9685bc2fb3b9f0220f3f598</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_MTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeae94ca21d099378d112215a30bac5ea31</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_AX25</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeae94173efea22c7d9f7cf5794bda60aa4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPIP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaa16dd3a301dcbc54559e455faa214812</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_MICP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaa0922213e13e21bdc6fc47e3bb8cb4b3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SCC_SP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaddac121f42d652639b9f1a4ab6334063</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ETHERIP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea4a7ee55e10ffa2889ec864061dfd9b9c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ENCAP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeab986fd0f9979b7ac8e455cbdc9a04f1c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ANY_PRIV_ENC</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeae6f6341420590c4c0040bbf83431ea17</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_GMTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea75d6d6bc3194fc7c7f599bec6c8bed2a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IFMP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeae8deddd55ef97c55b1707eb27120eb6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_PNNI</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea4e650d53603aa759da5fb46f782c7e56</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_PIM</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaec3d01e4d23894337b910be097850f23</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ARIS</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeac43b97e29a7379567ee6251c769bd8e5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SCPS</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeafb9e0fa6695a4f06fd7301d447626e3c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_QNX</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaa2e009b3e9fdcd0df179541b4759dc78</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_AN</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaaee72de21586a71ec9c1de6d26103d1c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPComp</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea005d08c204eb3c9ce4fda7c5fc4878e1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SNP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea8a22527178dadb5364f7db341ffeabdf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_Compaq_Peer</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeab461495ddf6658ccc480ebeb206164b1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPX_in_IP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea97059663628127b1738ab943f2a9a328</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_VRRP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea438c7667da58dc528ebca5585434395f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_PGM</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea9b0f254b4d98d7400ccca0e118e5fc37</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ANY_ZERO_HOP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea7deb4eda317e225c0e27d77a3567f74e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_L2TP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea58bd0e0146b11ee58c6d32174222cf71</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_DDX</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeabe680f2fc13b17024c29652b1518ebb5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IATP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaf87e18441522469fb469e52e1d61906e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_STP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea2ab5fe4b262d01b655f3c925836e15a6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SRP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea06e1214849c2b9dc1cfff07e56e925e4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_UTI</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea6877ea94d0755a7204ff222e19c79e95</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SMP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaecc99400bff657c2154f4594f37facb0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SM</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea2487fe9fb7cd4bdaa17b2c657ba15018</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_PTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeab4f0e82e3b661d2de0c4d78eb03c5bc3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_ISIS</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea1a55c6e1112e448829b94b4091c71e7a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_FIRE</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea38e6407861f800399ec1a34ec0fde2a4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_CRTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea838510d7c0e658ee495c6f0dfbafbb91</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_CRUDP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeab56bfcfdcf725c415669866200591241</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SSCOPMCE</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea8fe3318bbe97b7715d8ff65d83a5749e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_IPLT</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeafc93dfcadfa47d380c5d9a392dca117f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SPS</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeac588ec81d589776abbcf05424414f920</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_PIPE</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeab3c05bc815d37d488645a9a605e883b8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_SCTP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea02944136413e06785c6cbd44f52359e3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_FC</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaaafd42469743174f7fb479a473a3a035</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_RSVP_E2E_IGNORE</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaf96abbab80993204b88377ca806d4235</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_Mobility_Header</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeabc2a94748b995a2c3068d534f65d604a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_UDPLite</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea0f2f4b0c97c3919d1c1db0742ae80af4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_MPLS_in_IP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea42147d339151a3053ddcb842e92fa187</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_manet</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea7d7940d2179419a2dfefe6c2242032a7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_HIP</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea37643c9ab3ed8de3edd86dc9e05e562a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_Shim6</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea5d9aea6e62dbac43c596bc996dfc025a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_EXP1</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea9c841d3e3f7f40a12b5b6851e87dd61b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_EXP2</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aea0f8c7369c55e0c77d35a9de71a4a21a9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_PROTO_Reserved</name>
+ <anchorfile>tnet__proto_8h.html</anchorfile>
+ <anchor>a0a5a9fc22fd159c4a6c3ba14951133aeaed0bace331ff7d5ce6a0fcffa58cfd2d</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_socket.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__socket_8c</filename>
+ <includes id="tnet__socket_8h" name="tnet_socket.h" local="yes" imported="no">tnet_socket.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <member kind="function">
+ <type>tnet_socket_t *</type>
+ <name>tnet_socket_create_2</name>
+ <anchorfile>group__tnet__socket__group.html</anchorfile>
+ <anchor>gaa4d96c3d0bac908bd2d3413fbd19d30d</anchor>
+ <arglist>(const char *host, tnet_port_t port_, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_socket_t *</type>
+ <name>tnet_socket_create</name>
+ <anchorfile>group__tnet__socket__group.html</anchorfile>
+ <anchor>ga44cfc3407bc375c5b932bfe45a9de849</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_socket_def_t</name>
+ <anchorfile>tnet__socket_8c.html</anchorfile>
+ <anchor>a0b84352684cbba68fd098ba5801da787</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_socket.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__socket_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <includes id="tnet__tls_8h" name="tnet_tls.h" local="yes" imported="no">tls/tnet_tls.h</includes>
+ <includes id="tnet__dtls_8h" name="tnet_dtls.h" local="yes" imported="no">tls/tnet_dtls.h</includes>
+ <class kind="struct">tnet_socket_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IPV4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a74e1b90dfbc2a5eb72f86e20c3391b59</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_UDP</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a4a39d9f77a2c0f974f3a5ebb8a80992d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_DTLS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>abce7f796c5fca03a606ce218950650d2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_TCP</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>aa95c678d99efa12a7a5400f8b82ddad5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_TLS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>aca18b3796e1a0244078292db73a5c20e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SCTP</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a48fcfca9ecec785918601fd863ba10cf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_WS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a542569e83b7300b1f231843e1c796d05</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_WSS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a2ec694b5b9296070f6cfac1ab5344f38</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IPSEC</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a63282a2cae8654c1d2882662580d05ea</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IPV6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>aa41f8ec0c07e2ee94feb2b6be80fca2a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IPV46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>aed444b967bd2b8f0bd89b4b3c80d8762</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_IS_VALID</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>aaea09b2a77f6f12d48823836a8f44e3c</anchor>
+ <arglist>(socket)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_VALID</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>abb72c89f5e4637106faf36e5dfa4c004</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_STREAM</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a524680417e129af2019545bef449225f</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_DGRAM</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a33975122769a5a67cbeccaee9eb9a97b</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_IPV4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a8eeb8682e7f29f4eda0b53e4a2d23b73</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_IPV6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a0b6df4149ae8f6b96974152b910cf518</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_IPV46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a1c7630358e600dfea260ef4de88a04cd</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_IPSEC</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a691d1054b9ba60c8acfd939ee1ac30e0</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_UDP</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>afed2197fb95bdd5b24a2241717b9785a</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_DTLS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a469601122019599b23d3abeba5b7aa94</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_TCP</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>aeb0cd6fa3f1666aa122242e90d2a8983</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_TLS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ae1ae1b3c50657b6202cfc962085db773</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_SCTP</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a502f2a14d70745355c989c7d171ccc6d</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_WS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ac377ded5b93456ca31d670c9c6dbf5b9</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_WSS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>af4e55c1c5ec20c90ee19c4ac14cbd30d</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_IS_SECURE</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ae71d33e0a1a343f2cf4d2e54f3370730</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_UNSET</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab4ef32a80f5d86de4033f2b0467cf848</anchor>
+ <arglist>(type, OP)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_IPV4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a97be443ebd7a06b835cd545eed66d3dc</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_IPV4Only</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>aba4aad26261c9807d70f6fb2020d684a</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_IPV6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a53363b809815b0fdbcc8b2b3e52d08b0</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_IPV6Only</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a1b5a72e73a32f688d1c22a3b6ce20804</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_IPSEC</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>aadb0b3ed0d2be77ea464ddcffba4b36d</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_UDP</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a2db025967772ce44fb5844b9e70b02ea</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_DTLS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a78be84fa580e6b474cf3d060b050e91f</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_TCP</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a901c93fdc876a6787bf71867318e3f80</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_TLS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a69a1c4e47a7412f8739d922dd294c1d6</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_SCTP</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a2520e87cbac118e7de1dc8062f534271</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_WS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a8c4a5116f4ac9a8c3165233573aeb67b</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_TYPE_SET_WSS</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a21f939504f60fab74e3059a324c72fa0</anchor>
+ <arglist>(type)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_HOST_ANY</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>aa6e6dcfb2a211eed85fe668cfc0c3632</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_SOCKET_PORT_ANY</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ad247279879162ea5d5484ce8e9b244fb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS enum tnet_socket_type_e</type>
+ <name>tnet_socket_type_t</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a576cd9bf9d800834987f993c8f6c17e1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_socket_s</type>
+ <name>tnet_socket_t</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a25420c64ae82e009d5e593315c02a8a3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_socket_t</type>
+ <name>tnet_socket_udp_t</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a4b3efb6a5a35e78092888202401e1c5e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_socket_t</type>
+ <name>tnet_socket_tcp_t</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a23360f55c1880d6abea27966a299ee96</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_socket_t</type>
+ <name>tnet_socket_tls_t</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a84d882faf5cb0e466532c54b05c36036</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_socket_t</type>
+ <name>tnet_socket_ws_t</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a9a1ca8a86fbfc3bf4dceb177506358c3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_socket_t</type>
+ <name>tnet_socket_wss_t</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a3d437e9d3ee3d89d3587575816786f60</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tnet_socket_t</type>
+ <name>tnet_socket_ipsec_t</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a02562d642430b5eee0000d90e96af005</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_sockets_L_t</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ac361e0e716e059ae9ef1f51d01e817a6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_socket_type_e</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_invalid</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba4867e88cadabdb296e11da6cd8374e81</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_udp_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba9878c017dac96d17dfb8ff6f90f7f119</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_dtls_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbad478122de9e6c0d8b5218c5c21cda411</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tcp_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba040c10bb67bd4ac2eaf26fb3548484bc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tls_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba06c82b0a6be847347a4f7bb7a4627df6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_sctp_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba27609c62adde9edffb8a8c46d2df5f87</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_ws_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba8c0daa338550cf5701428c1516cf5439</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_wss_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbac8516012b70312ab8d7c341e7e4deb64</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_udp_ipsec_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbacf582a552aa9901a7863f6d2e1e156fe</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_dtls_ipsec_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbaf0f8dd6e0fab9c10f61021035f056f0a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tcp_ipsec_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbad65dcbd7cf453cfde4d4e855c912733e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tls_ipsec_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba578b670c64d83c907a4fca82b0bb308c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_sctp_ipsec_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba7cc7206c5c80e58a1d29b8fac81d589c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_ws_ipsec_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba751d905a4a5a4631b09f506859ccf918</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_wss_ipsec_ipv4</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba935a0985c07a4c49317ef88d80e78a11</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_udp_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba12b789591e7ded6685e3809a2d63133b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_dtls_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba90a963ee591fb48b0f520bab62a85c23</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tcp_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba6101c967b4d3ce42af97d9fc25334131</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tls_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba1d6b4fdddc80aa1b12e735e3235c939f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_sctp_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbaf8ce34f17339807de6fba014675c2cea</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_ws_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba0121d29620c9bea409c293d1f44a53f0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_wss_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba6b4f8a51b95f79db7b998038d0b17a47</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_udp_ipsec_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba2af7612a9b8b9de23693a56f63fc3294</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tcp_ipsec_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba3fba0645a3ff38ace6a902c634c0735e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tls_ipsec_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbadd2b59ff43c54857d0879ba551dc4d72</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_sctp_ipsec_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbaee18824f664be3a782685568110ebd7e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_ws_ipsec_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba0528c055b394dfb54e98fb89b92bfeca</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_wss_ipsec_ipv6</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba75db9cfd6290a9b3825e4869a10e4207</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_udp_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba63e7d80e87188729eab2445346144e73</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_dtls_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba050969bd5ae7693d610006dfe3cdc8f6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tcp_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba229d0cef3abe327bbef97e8ba800bc6c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tls_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbaef5605551def96072ef6a422f93f4d66</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_sctp_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba21d71335634ff4fe2ec328560ee6f608</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_ws_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba738eb76803f30691a46e91c62713302e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_wss_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba9d0241d8fc72284aaf570fcc9828ffeb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_udp_ipsec_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbabca42b8ab7ee8f53bd5e7142eb683d38</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_dtls_ipsec_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbaf5d5d8170cd35b0b32c74d818e85233d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tcp_ipsec_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba9b1ab58092d574e6754634b1e673c62e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_tls_ipsec_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbabeef19aa4eb525b42ac2ef840239205e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_sctp_ipsec_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba4d0c11246cdd62f0271b15e9ecf85e3d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_ws_ipsec_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bba798031e7b87799cb4502d865950bc1c6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_socket_type_wss_ipsec_ipv46</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>ab37bfdb5ac374384872091d48e3895bbad3d316ccc36b63c9cd55da308846c9b9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_socket_t *</type>
+ <name>tnet_socket_create_2</name>
+ <anchorfile>group__tnet__socket__group.html</anchorfile>
+ <anchor>gaa4d96c3d0bac908bd2d3413fbd19d30d</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_socket_t *</type>
+ <name>tnet_socket_create</name>
+ <anchorfile>group__tnet__socket__group.html</anchorfile>
+ <anchor>ga44cfc3407bc375c5b932bfe45a9de849</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_socket_def_t</name>
+ <anchorfile>tnet__socket_8h.html</anchorfile>
+ <anchor>a1c58ffbcdb15d377d4075335ea8001a3</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_transport.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__transport_8c</filename>
+ <includes id="tnet__transport_8h" name="tnet_transport.h" local="yes" imported="no">tnet_transport.h</includes>
+ <includes id="tnet__tls_8h" name="tnet_tls.h" local="yes" imported="no">tls/tnet_tls.h</includes>
+ <includes id="tnet__dtls_8h" name="tnet_dtls.h" local="yes" imported="no">tls/tnet_dtls.h</includes>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_CIPHER_LIST</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a0272165dcd11efdaf43bac2d288a9a0e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_prepare</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>aafdc2431c02385e300c520ca985ed55b</anchor>
+ <arglist>(tnet_transport_t *transport)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_unprepare</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a9763a05c45da16d31e3c99a79fdf1761</anchor>
+ <arglist>(tnet_transport_t *transport)</arglist>
+ </member>
+ <member kind="function">
+ <type>void *TSK_STDCALL</type>
+ <name>tnet_transport_mainthread</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a7fb95b1359ad08465766812b225cb579</anchor>
+ <arglist>(void *param)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_stop</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a4dc920abb12866b5154692fa31885d99</anchor>
+ <arglist>(tnet_transport_t *transport)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_transport_t *</type>
+ <name>tnet_transport_create</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a395c18a684a068680a8a1d33fe2e05b7</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type, const char *description)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_transport_t *</type>
+ <name>tnet_transport_create_2</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>aab38b03dc47731a7b0ccdae1937f3f46</anchor>
+ <arglist>(tnet_socket_t *master, const char *description)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_transport_event_t *</type>
+ <name>tnet_transport_event_create</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a14597eb136e537f1d4d4e5ce3b884b63</anchor>
+ <arglist>(tnet_transport_event_type_t type, const void *callback_data, tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_tls_set_certs</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a894866de936b19458529ba4ca96bfaad</anchor>
+ <arglist>(tnet_transport_handle_t *handle, const char *ca, const char *pbk, const char *pvk, tsk_bool_t verify)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_start</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a505614c61dd978a668d82b827727e086</anchor>
+ <arglist>(tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_issecure</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a9b7747658fa19bf00991b51e300f38aa</anchor>
+ <arglist>(const tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_transport_get_description</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a47a6418d80182973b2a1d590a3121bca</anchor>
+ <arglist>(const tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_get_ip_n_port</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a47145a97b9d61dd54920479755addda6</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_get_ip_n_port_2</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>aaaabe13c957df654256b2e9ea31e9b10</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_set_natt_ctx</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a5e2f170d3cdb1d161a7be4225b9d2c2e</anchor>
+ <arglist>(tnet_transport_handle_t *handle, tnet_nat_context_handle_t *natt_ctx)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_get_public_ip_n_port</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>adaa653753ccbf3a5c9bfb0ea26cfb985</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_transport_dtls_get_local_fingerprint</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>ade804a4fc6cb8143eeaad0fd1f62c91f</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_dtls_hash_type_t hash)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_dtls_use_srtp</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>aa0647587ca32a91c1238351b0a423f36</anchor>
+ <arglist>(tnet_transport_handle_t *handle, const char *srtp_profiles, struct tnet_socket_s **sockets, tsk_size_t sockets_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_dtls_set_remote_fingerprint</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a4cc2b127f08b567b3f1b47b33d27d8b9</anchor>
+ <arglist>(tnet_transport_handle_t *handle, const tnet_fingerprint_t *fingerprint, tnet_dtls_hash_type_t hash, struct tnet_socket_s **sockets, tsk_size_t sockets_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_transport_dtls_is_enabled</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>aebb3e8611b3dec54cd65c2b41f9ea92d</anchor>
+ <arglist>(const tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_dtls_set_enabled</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>acebacaf2c4236d879be5d3d94ef4a67b</anchor>
+ <arglist>(tnet_transport_handle_t *handle, tsk_bool_t enabled, struct tnet_socket_s **sockets, tsk_size_t sockets_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_dtls_set_setup</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>acf4762d81cfd8832a80672f1d216e2ed</anchor>
+ <arglist>(tnet_transport_handle_t *handle, tnet_dtls_setup_t setup, struct tnet_socket_s **sockets, tsk_size_t sockets_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_dtls_do_handshake</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a7e7cbd1d1d1b4c8cdaa7d081141259a6</anchor>
+ <arglist>(tnet_transport_handle_t *handle, struct tnet_socket_s **sockets, tsk_size_t sockets_count, const struct sockaddr_storage **remote_addrs, tsk_size_t remote_addrs_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_socket_type_t</type>
+ <name>tnet_transport_get_type</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>ab5732e5c7845d6cb39cdda33bc347dd3</anchor>
+ <arglist>(const tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_fd_t</type>
+ <name>tnet_transport_get_master_fd</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>aa745da0b969e4f7fe05884929b331fb8</anchor>
+ <arglist>(const tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_fd_t</type>
+ <name>tnet_transport_connectto</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a4199eaa8e910079521330730e8faefb4</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, const char *host, tnet_port_t port, tnet_socket_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_set_callback</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>adebb516df3a574bf4192ceea1060febe</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_transport_cb_f callback, const void *callback_data)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_transport_shutdown</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a89e04cc29fbf6f856055e092c54cd9ea</anchor>
+ <arglist>(tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_transport_def_t</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>add6f857e2ce9fa399da32f65d9c6ed42</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_transport_event_def_t</name>
+ <anchorfile>tnet__transport_8c.html</anchorfile>
+ <anchor>a537e63cab92a28745e37c389813a5812</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_transport.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__transport_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__socket_8h" name="tnet_socket.h" local="yes" imported="no">tnet_socket.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <includes id="tnet__nat_8h" name="tnet_nat.h" local="yes" imported="no">tnet_nat.h</includes>
+ <class kind="struct">tnet_transport_event_s</class>
+ <class kind="struct">tnet_transport_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>DGRAM_MAX_SIZE</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a303845dce0d691a1fd531da3a49b815d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>STREAM_MAX_SIZE</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a0022d825df5d3de6c3a1bd74f76030ad</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TRANSPORT_CB_F</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>ad21c17552c1931c2326fa1febacdd2af</anchor>
+ <arglist>(callback)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_transport_connectto_2</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>aed1a2d620b05906167e9f59f20d249fd</anchor>
+ <arglist>(handle, host, port)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_transport_dtls_set_certs</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>ad735ab3e4ee5f9760226bd5e024fd2d6</anchor>
+ <arglist>(self, ca, pbk, pvk, verify)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_transport_dtls_srtp_set_certs</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a8bd4050682a0194cf1f9cd58cf4e63d0</anchor>
+ <arglist>(self, ca, pbk, pvk, verify)</arglist>
+ </member>
+ <member kind="typedef">
+ <type>void</type>
+ <name>tnet_transport_handle_t</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a5c5148c35787a35dabdc83e71b6337c9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_transport_event_type_e</type>
+ <name>tnet_transport_event_type_t</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>acdbc1d61b4bdd46f3d5cb8db8e077397</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_transport_event_s</type>
+ <name>tnet_transport_event_t</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a093af931f4723f331238a2be0a8f5d71</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>int(*</type>
+ <name>tnet_transport_cb_f</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>af1e810a07af093bdd8b84528a906cef2</anchor>
+ <arglist>)(const tnet_transport_event_t *e)</arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_transport_s</type>
+ <name>tnet_transport_t</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>ab8f9d63467d6c16f5d9e8400705f46f3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_transport_event_type_e</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_data</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5ba8f94c6e260626ca15997e0384a6a34f1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_closed</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5baabebea7f92e558c8e09fe1f79b434c1c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_error</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5babf46e68136f9cb4d34130283a775a202</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_removed</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5ba0cd9c3fadb25a5aa52a867c05798982b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_connected</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5ba56ba0a0c0f79ca66025f8a32c28a9b44</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_accepted</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5bad931ba02a9181775756c4e40d9e540bc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_dtls_handshake_started</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5ba6bd61302adcb28659548f1855d6a7266</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_dtls_handshake_succeed</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5ba2a0f8e9915fa839e00dfcd35400ba7eb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_dtls_handshake_failed</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5ba299a1d91f87662ebfc331568cc68208f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_dtls_fingerprint_mismatch</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5ba9a5daf572cd52c02dc603296b914d3d9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_dtls_srtp_data</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5ba6ce922aa5ef586d6af2f6375bb0d7eb7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_dtls_srtp_profile_selected</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5baaa14922cdd57d1d3381630c443a39c2a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>event_dtls_error</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abbf94f6cbb0048f5f737fb0fb850ab5ba7a5615d24a55510ce08dc51f25ee09df</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_tls_set_certs</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a13c127e8c4117a4b700ac5a491ea1a90</anchor>
+ <arglist>(tnet_transport_handle_t *self, const char *ca, const char *pbk, const char *pvk, tsk_bool_t verify)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_start</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a2a387a33860dee5a55a31ee1ba3997cf</anchor>
+ <arglist>(tnet_transport_handle_t *transport)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_issecure</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>ae297b8dcbd3f82f3e51335ef1c542659</anchor>
+ <arglist>(const tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API const char *</type>
+ <name>tnet_transport_get_description</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>aa1964324e317dcc38893c6ad482b4e6e</anchor>
+ <arglist>(const tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_get_ip_n_port</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>aa5a9608d24db9099a6511224fd3471c4</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_get_ip_n_port_2</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>ae6d44bddc3ef0e6d04f64eaaf1e222bd</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_set_natt_ctx</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a220be41b652653fbe3a0724f0091ea29</anchor>
+ <arglist>(tnet_transport_handle_t *handle, tnet_nat_context_handle_t *natt_ctx)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_get_public_ip_n_port</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a1c466c2c9934b0a1291c11a9e0dd423a</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_isconnected</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a38e55eab24973fbb9a44062e51d1df75</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_have_socket</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a2fe2a1b3010b9863f70be84209d85e8b</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API const tnet_tls_socket_handle_t *</type>
+ <name>tnet_transport_get_tlshandle</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a086def0ecfd39c41becf8ce271602477</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_add_socket</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a4ddc0942b34eb9127fea1c811627f78a</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t *tlsHandle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_pause_socket</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a5d8f7a60ac7d836e8167195a62fa1151</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t fd, tsk_bool_t pause)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_remove_socket</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a0f4b9a66fce9e219c2d61cffeda27ab4</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t *fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_fd_t</type>
+ <name>tnet_transport_connectto</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>aa262527a36bd4651a46edfdbe837487b</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, const char *host, tnet_port_t port, tnet_socket_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_size_t</type>
+ <name>tnet_transport_send</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>aa50503da55477a13caffc15d75e0dbf3</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t from, const void *buf, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_size_t</type>
+ <name>tnet_transport_sendto</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>aa4a559c780cb647d80d3345e0598930a</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void *buf, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_set_callback</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a30977582f872b66ea7a3f3175853b1cc</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_transport_cb_f callback, const void *callback_data)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API const char *</type>
+ <name>tnet_transport_dtls_get_local_fingerprint</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a54db6ae9e13d34cbd08b5508a1a8d8aa</anchor>
+ <arglist>(const tnet_transport_handle_t *handle, tnet_dtls_hash_type_t hash)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_dtls_use_srtp</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a7716418ff59ea68f572db3a059993db7</anchor>
+ <arglist>(tnet_transport_handle_t *handle, const char *srtp_profiles, struct tnet_socket_s **sockets, tsk_size_t sockets_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_dtls_set_remote_fingerprint</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a6bea98bd13e69f696b5268e7f032504d</anchor>
+ <arglist>(tnet_transport_handle_t *handle, const tnet_fingerprint_t *fingerprint, tnet_dtls_hash_type_t hash, struct tnet_socket_s **sockets, tsk_size_t sockets_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_bool_t</type>
+ <name>tnet_transport_dtls_is_enabled</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>aaa6fca161f564e8586ba38b487cece20</anchor>
+ <arglist>(const tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_dtls_set_enabled</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>ab4e5fe447eca34dbb555d96b4bfb1405</anchor>
+ <arglist>(tnet_transport_handle_t *handle, tsk_bool_t enabled, struct tnet_socket_s **sockets, tsk_size_t sockets_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_dtls_set_setup</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>abb8f01a636827641262a8fcd9cb3d0bb</anchor>
+ <arglist>(tnet_transport_handle_t *handle, tnet_dtls_setup_t setup, struct tnet_socket_s **sockets, tsk_size_t sockets_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_dtls_do_handshake</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a6478aee395b8a66c7ac15a43840c3682</anchor>
+ <arglist>(tnet_transport_handle_t *handle, struct tnet_socket_s **sockets, tsk_size_t sockets_count, const struct sockaddr_storage **remote_addrs, tsk_size_t remote_addrs_count)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_socket_type_t</type>
+ <name>tnet_transport_get_type</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a33ffcdc497c1550202731abaaf05b8ab</anchor>
+ <arglist>(const tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_fd_t</type>
+ <name>tnet_transport_get_master_fd</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a93691e2da74102b4814817aa997b3b67</anchor>
+ <arglist>(const tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_transport_shutdown</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a79a3f3604ec1cb059c8b2d319d163e87</anchor>
+ <arglist>(tnet_transport_handle_t *handle)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_object_t *</type>
+ <name>tnet_transport_context_create</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a158a59ec9e717cbbab586e299e4cd866</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_transport_t *</type>
+ <name>tnet_transport_create</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a7b5874cdbc14ee5107151244857bfbd1</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type, const char *description)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_transport_t *</type>
+ <name>tnet_transport_create_2</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a55fde6bcc30dcd6ab80e9449c2ec6d88</anchor>
+ <arglist>(tnet_socket_t *master, const char *description)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_transport_event_t *</type>
+ <name>tnet_transport_event_create</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a14597eb136e537f1d4d4e5ce3b884b63</anchor>
+ <arglist>(tnet_transport_event_type_t type, const void *callback_data, tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_transport_def_t</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>a9828b22dcbec0f1c54ededd31fd39490</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_transport_event_def_t</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>afb173e3ef8b21f78740052af526e69f3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_transport_context_def_t</name>
+ <anchorfile>tnet__transport_8h.html</anchorfile>
+ <anchor>acfd90b5ed268b13b24f377992954d065</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_transport_cfsocket.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__transport__cfsocket_8c</filename>
+ <includes id="tnet__transport_8h" name="tnet_transport.h" local="yes" imported="no">tnet_transport.h</includes>
+ </compound>
+ <compound kind="file">
+ <name>tnet_transport_poll.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__transport__poll_8c</filename>
+ <includes id="tnet__transport_8h" name="tnet_transport.h" local="yes" imported="no">tnet_transport.h</includes>
+ </compound>
+ <compound kind="file">
+ <name>tnet_transport_win32.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__transport__win32_8c</filename>
+ <includes id="tnet__transport_8h" name="tnet_transport.h" local="yes" imported="no">tnet_transport.h</includes>
+ </compound>
+ <compound kind="file">
+ <name>tnet_types.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__types_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_FINGERPRINT_MAX</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>afe5781b6502203e6d121aa86a998c72f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_INVALID_SOCKET</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a6f5bbd2094794d14c754526899ed3555</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ERROR_WOULDBLOCK</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a6b07aaef86d309e376f2b84c8e47371d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ERROR_INPROGRESS</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a6ea526bb93648fb77f7c4c64663c9768</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ERROR_CONNRESET</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a7c721d5339257e316df23f5d72da8061</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ERROR_INTR</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>ab678436a332c2e2da1c3036bd0fda68c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ERROR_ISCONN</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a2e226a2261679abd9369fe7df869953e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ERROR_EAGAIN</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>afd4439f649d80deea1da5ba4b9f407ae</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_gai_strerror</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>aabe506ad80551db8d5687e48afaa3d3e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_INVALID_FD</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a78ffc6813a665347c56c3dbc2b59e084</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>int32_t</type>
+ <name>tnet_fd_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>ad310050a573244ca7810e0b11c2d2363</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>uint16_t</type>
+ <name>tnet_port_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a3a4edd243b59f5b9e3b0a2bfaa74fcd0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>int32_t</type>
+ <name>tnet_family_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a7e6c5c9f3462512e8093438daf3f4d3b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>char</type>
+ <name>tnet_host_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a0e365398826bc67ee809d5d8619cff6f</anchor>
+ <arglist>[NI_MAXHOST]</arglist>
+ </member>
+ <member kind="typedef">
+ <type>char</type>
+ <name>tnet_ip_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a317920febe452aa28432d0df4d448694</anchor>
+ <arglist>[INET6_ADDRSTRLEN]</arglist>
+ </member>
+ <member kind="typedef">
+ <type>unsigned char</type>
+ <name>tnet_fingerprint_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>ae170648503e4db4d27f097f59dc0bcd5</anchor>
+ <arglist>[TNET_FINGERPRINT_MAX+1]</arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_interfaces_L_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a08fde7fadc3d2f2f5a654ebe5d51c5d9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_addresses_L_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>af5b5e78f9d75c00cbff4aabee7d4e534</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dtls_setup_e</type>
+ <name>tnet_dtls_setup_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a7a5ada4bc5b60674bf52c2fcd4cf354c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_dtls_hash_type_e</type>
+ <name>tnet_dtls_hash_type_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a90e3b533ed21bcbf0c31113405c0bf14</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>char</type>
+ <name>tnet_error_t</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a79e339c2bb6c0e841bce06c380c6d376</anchor>
+ <arglist>[512]</arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dtls_setup_e</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a7a2f346b4438e78d7096d08bcfd8ce51</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_setup_none</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a7a2f346b4438e78d7096d08bcfd8ce51ada8cd208467a4f2e36638b997bd52ec5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_setup_actpass</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a7a2f346b4438e78d7096d08bcfd8ce51a843e99bce81a983533499a2813684995</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_setup_active</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a7a2f346b4438e78d7096d08bcfd8ce51ae85331edf6e6d15edde3a8336eb52509</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_setup_passive</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a7a2f346b4438e78d7096d08bcfd8ce51ad7fdba2fdb1911557ad82dc4be40e57e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_DTLS_SETUP_MAX</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a7a2f346b4438e78d7096d08bcfd8ce51ae8e3e4805b16d3212c4c53daa8336cb2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_dtls_hash_type_e</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a9a098624f10ecf3c9bdd16867d22ef79</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_hash_type_none</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a9a098624f10ecf3c9bdd16867d22ef79a3b5f26eb71f64f135c4588d82d3ff798</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_hash_type_md5</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a9a098624f10ecf3c9bdd16867d22ef79abdd2c218483e6a22a00003f808691a63</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_hash_type_sha1</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a9a098624f10ecf3c9bdd16867d22ef79a70d72aada5320cab9d31e007039bd5e6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_hash_type_sha256</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a9a098624f10ecf3c9bdd16867d22ef79a2408f43f4ebc54c26808dad5166bd4db</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>tnet_dtls_hash_type_sha512</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a9a098624f10ecf3c9bdd16867d22ef79a00de2ff7b734266d98a2cd5501620619</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>TNET_DTLS_HASH_TYPE_MAX</name>
+ <anchorfile>tnet__types_8h.html</anchorfile>
+ <anchor>a9a098624f10ecf3c9bdd16867d22ef79ae4fa7baa3b729d8600fb6d62868a9887</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_utils.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__utils_8c</filename>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">tnet_utils.h</includes>
+ <includes id="tnet__socket_8h" name="tnet_socket.h" local="yes" imported="no">tnet_socket.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">tnet_endianness.h</includes>
+ <includes id="tnet__dns__resolvconf_8h" name="tnet_dns_resolvconf.h" local="yes" imported="no">dns/tnet_dns_resolvconf.h</includes>
+ <member kind="define">
+ <type>#define</type>
+ <name>AF_LINK</name>
+ <anchorfile>tnet__utils_8c.html</anchorfile>
+ <anchor>a7a40a39aa9dfaf771780ebe061ffa940</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_interface_t *</type>
+ <name>tnet_interface_create</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga519d8f6f2415bdf328e364f61bb47a39</anchor>
+ <arglist>(const char *description, const void *mac_address, tsk_size_t mac_address_length)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_address_t *</type>
+ <name>tnet_address_create</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga3e826cd2939bd297a73802b860262003</anchor>
+ <arglist>(const char *ip)</arglist>
+ </member>
+ <member kind="function">
+ <type>void</type>
+ <name>tnet_getlasterror</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gac2b13fc342bfffa18868d8d91596961f</anchor>
+ <arglist>(tnet_error_t *error)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_geterrno</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaf5def7b9d46329d20e8939a98482603f</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_interfaces_L_t *</type>
+ <name>tnet_get_interfaces</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gad982a81d6170a3e4826180ff72efe5fe</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_addresses_L_t *</type>
+ <name>tnet_get_addresses</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga6c6add3dc5bdf1f3b9cddd4430254fc4</anchor>
+ <arglist>(tnet_family_t family, tsk_bool_t unicast, tsk_bool_t anycast, tsk_bool_t multicast, tsk_bool_t dnsserver, long if_index)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_getbestsource</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gac336e82f244c99e56b440b3b55c60c6a</anchor>
+ <arglist>(const char *destination, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t *source)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_getaddrinfo</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga36ace730e3924849994ea87548d495be</anchor>
+ <arglist>(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)</arglist>
+ </member>
+ <member kind="function">
+ <type>void</type>
+ <name>tnet_freeaddrinfo</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga18b2d2888f220d3117ee3b681c464922</anchor>
+ <arglist>(struct addrinfo *ai)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_getsockname</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaa1646c470ce392009805d7b46e5fe085</anchor>
+ <arglist>(tnet_fd_t fd, struct sockaddr_storage *result)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_getpeername</name>
+ <anchorfile>tnet__utils_8c.html</anchorfile>
+ <anchor>a90fda61ebce05fdb19b09bcdfa9fd3f6</anchor>
+ <arglist>(tnet_fd_t fd, struct sockaddr_storage *result)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_socket_type_t</type>
+ <name>tnet_get_socket_type</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gac13e28b8f1c767306245bd3bf13f5e3c</anchor>
+ <arglist>(tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_family_t</type>
+ <name>tnet_get_family</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga00003bf6a8749b31d4b60b09cf5337a3</anchor>
+ <arglist>(const char *host, tnet_port_t port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_get_sockip_n_port</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga66eefd3c3bb0cc2c7a287374449b700e</anchor>
+ <arglist>(const struct sockaddr *addr, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_get_peerip_n_port</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga9a18f5ae763f323f38200e11b9ba369d</anchor>
+ <arglist>(tnet_fd_t localFD, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_get_ip_n_port</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga7feb0af8302b35bf835036ab7a48c4e9</anchor>
+ <arglist>(tnet_fd_t fd, tsk_bool_t getlocal, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_getnameinfo</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga043fd7c4105a0d2014f3e0670b888d94</anchor>
+ <arglist>(const struct sockaddr *sa, socklen_t salen, char *node, socklen_t nodelen, char *service, socklen_t servicelen, int flags)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_gethostname</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga906ade6f28556babf47cb08dc947abd1</anchor>
+ <arglist>(tnet_host_t *result)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_waitUntil</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga3365d143e90fc4a1f83d330f489feb08</anchor>
+ <arglist>(tnet_fd_t fd, long timeout, tsk_bool_t writable)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_joingroup6</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga39276ddf27fe08518cf2431ae46a2045</anchor>
+ <arglist>(tnet_fd_t fd, const char *multiaddr, unsigned iface_index)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_leavegroup6</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaf54873a5fed045c9eff1200ebb368266</anchor>
+ <arglist>(tnet_fd_t fd, const char *multiaddr, unsigned iface_index)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_resolve</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga903b843f79e03448a90d70bdd92a4779</anchor>
+ <arglist>(const char *fqdn, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t *out_ip, tnet_port_t *out_port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockaddrinfo_init</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaeb05ffebc3d308fd2ebb39de546c70a5</anchor>
+ <arglist>(const char *host, tnet_port_t port, enum tnet_socket_type_e type, struct sockaddr_storage *ai_addr, int *ai_family, int *ai_socktype, int *ai_protocol)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockaddr_init</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga0449294a58b8db4f81d835af2a535b90</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_init</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga02e3ba851395a9688b964cc228b732a8</anchor>
+ <arglist>(const char *host, tnet_port_t port, enum tnet_socket_type_e type, tnet_fd_t *fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_set_mode</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gab9616a14cc2c468ad99b510e276abac0</anchor>
+ <arglist>(tnet_fd_t fd, int nonBlocking)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_sendto</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga92fcf0392c9a93e2e578578479d4f35e</anchor>
+ <arglist>(tnet_fd_t fd, const struct sockaddr *to, const void *buf, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_recvfrom</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gabbf0cddd16af300a66d0859ed79b3cda</anchor>
+ <arglist>(tnet_fd_t fd, void *buf, tsk_size_t size, int flags, struct sockaddr *from)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_size_t</type>
+ <name>tnet_sockfd_send</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga93356b04edf02a163bfaa421676f1efc</anchor>
+ <arglist>(tnet_fd_t fd, const void *buf, tsk_size_t size, int flags)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_recv</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaba9d8246797b995ecfb81f42f1bd1b96</anchor>
+ <arglist>(tnet_fd_t fd, void *buf, tsk_size_t size, int flags)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_connectto</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gafe03cf813e644a3d2cd2de8666d7f9c8</anchor>
+ <arglist>(tnet_fd_t fd, const struct sockaddr_storage *to)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_listen</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga92a295abbf85a361ee5c609994e21f05</anchor>
+ <arglist>(tnet_fd_t fd, int backlog)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_fd_t</type>
+ <name>tnet_sockfd_accept</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gae4350aa61a296325ce5dfc34fae616f8</anchor>
+ <arglist>(tnet_fd_t fd, struct sockaddr *addr, socklen_t *addrlen)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_close</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gad13808723477879ca310a70c527d850a</anchor>
+ <arglist>(tnet_fd_t *fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_shutdown</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaba68ca319965780023e3209dae7167fa</anchor>
+ <arglist>(tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_interface_def_t</name>
+ <anchorfile>tnet__utils_8c.html</anchorfile>
+ <anchor>a86ced52797e3eb79032b310357338788</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_address_def_t</name>
+ <anchorfile>tnet__utils_8c.html</anchorfile>
+ <anchor>a4b41ff43f60511629f506e066fd57565</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_utils.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>tnet__utils_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__socket_8h" name="tnet_socket.h" local="yes" imported="no">tnet_socket.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <class kind="struct">tnet_interface_s</class>
+ <class kind="struct">tnet_address_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_CONNECT_TIMEOUT</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga2d7e6e8cff043b7f3c0bda66a7a728bd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_all</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>ab526869bb2226efadbe9b24fbeaa5bd9</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_all_unicast</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>add37eeae5ab502c5a41b713b52c6fbf4</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_unicast4</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a80c23788d4ee1faa50dd09dabf6b5888</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_unicast6</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a8308f69587e66f13587c758781b1ce06</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_all_anycast</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a320dbd3806f63877741e60fb562a8fdc</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_anycast4</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a38799bb6289ad0204fe2d321c0d88ffc</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_anycast6</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>aaa5c0dcb6c4d170162de234d4b39187b</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_all_multicast</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>ac8abdec533160f662824533eec17ae0b</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_multicast4</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a871424099f761764f01125ab50e27cd3</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_multicast6</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a19c1df691b3df50b7dc478cc4d516a6d</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_all_dnsservers</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a81dd24adc37519a2de448759ee44ccaf</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_dnsservers4</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>ab397bc8cc3d0a295c0260703b808fdfa</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_addresses_dnsservers6</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>aea0bfe2cc680f63140ac4854136846b9</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_ip</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a2017b5ef78a3f74af946a5681cf0e017</anchor>
+ <arglist>(fd, getlocal, ip)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_port</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a4c211f3c9cf30bab873cdfb673b90c7f</anchor>
+ <arglist>(fd, getlocal, port)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_sockip</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a96a295f733a973e755687eb18b76cafc</anchor>
+ <arglist>(addr, ip)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_sockport</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>aad605b48c4c0b260b8b2eda1ab3b3db4</anchor>
+ <arglist>(addr, port)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_peerip</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a079ef23d171be2c33c86d88276749b1d</anchor>
+ <arglist>(localFD, ip)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_peerport</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>aa7f35176e1af1f381db152a4e393c1bc</anchor>
+ <arglist>(localFD, port)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_get_sockaddr_size</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>aefb30f9ee6e1e8f5dd4e34727cd76bab</anchor>
+ <arglist>(psockaddr)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_ioctlt</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>ac2410f7b3e6a9d089408da51ef40bcf8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_soccket</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>af594457cda94f455aea25b5942d7cb79</anchor>
+ <arglist>(family, type, protocol)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_sockfd_waitUntilWritable</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>aeed8af0119b20431ad1a7789e61f2256</anchor>
+ <arglist>(fd, timeout)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_sockfd_waitUntilReadable</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>abe8fbe85cf4fb5526d8addee586f1714</anchor>
+ <arglist>(fd, timeout)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_sockfd_set_nonblocking</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a72e2456a98a5317aad673cdf5b14d229</anchor>
+ <arglist>(fd)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>tnet_sockfd_set_blocking</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a2840609d8aadb9b0f62be4fbe1b84591</anchor>
+ <arglist>(fd)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_PRINT_LAST_ERROR</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>ad84b1312befef0c09d4fa9a37e5bbe60</anchor>
+ <arglist>(FMT,...)</arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_interface_s</type>
+ <name>tnet_interface_t</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>a7c49ac3e5325961dd8c430edec84d106</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_address_s</type>
+ <name>tnet_address_t</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>abec2d2434c892e0b38503fba6e04d981</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API void</type>
+ <name>tnet_getlasterror</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gac2b13fc342bfffa18868d8d91596961f</anchor>
+ <arglist>(tnet_error_t *error)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_geterrno</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaf5def7b9d46329d20e8939a98482603f</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_interfaces_L_t *</type>
+ <name>tnet_get_interfaces</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gad982a81d6170a3e4826180ff72efe5fe</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_addresses_L_t *</type>
+ <name>tnet_get_addresses</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga6c6add3dc5bdf1f3b9cddd4430254fc4</anchor>
+ <arglist>(tnet_family_t family, tsk_bool_t unicast, tsk_bool_t anycast, tsk_bool_t multicast, tsk_bool_t dnsserver, long if_index)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_getbestsource</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gac336e82f244c99e56b440b3b55c60c6a</anchor>
+ <arglist>(const char *destination, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t *source)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_getaddrinfo</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga36ace730e3924849994ea87548d495be</anchor>
+ <arglist>(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API void</type>
+ <name>tnet_freeaddrinfo</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga18b2d2888f220d3117ee3b681c464922</anchor>
+ <arglist>(struct addrinfo *ai)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_getsockname</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaa1646c470ce392009805d7b46e5fe085</anchor>
+ <arglist>(tnet_fd_t fd, struct sockaddr_storage *result)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_getpeername</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>af7a97c97fbe63065150329bc02dd5cbb</anchor>
+ <arglist>(tnet_fd_t fd, struct sockaddr_storage *result)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_socket_type_t</type>
+ <name>tnet_get_socket_type</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gac13e28b8f1c767306245bd3bf13f5e3c</anchor>
+ <arglist>(tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_family_t</type>
+ <name>tnet_get_family</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga00003bf6a8749b31d4b60b09cf5337a3</anchor>
+ <arglist>(const char *host, tnet_port_t port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_get_ip_n_port</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga7feb0af8302b35bf835036ab7a48c4e9</anchor>
+ <arglist>(tnet_fd_t fd, tsk_bool_t getlocal, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_get_sockip_n_port</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga66eefd3c3bb0cc2c7a287374449b700e</anchor>
+ <arglist>(const struct sockaddr *addr, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_get_peerip_n_port</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga9a18f5ae763f323f38200e11b9ba369d</anchor>
+ <arglist>(tnet_fd_t localFD, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_getnameinfo</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga043fd7c4105a0d2014f3e0670b888d94</anchor>
+ <arglist>(const struct sockaddr *sa, socklen_t salen, char *node, socklen_t nodelen, char *service, socklen_t servicelen, int flags)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_gethostname</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga906ade6f28556babf47cb08dc947abd1</anchor>
+ <arglist>(tnet_host_t *result)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_waitUntil</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga3365d143e90fc4a1f83d330f489feb08</anchor>
+ <arglist>(tnet_fd_t fd, long timeout, tsk_bool_t writable)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_joingroup6</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga39276ddf27fe08518cf2431ae46a2045</anchor>
+ <arglist>(tnet_fd_t fd, const char *multiaddr, unsigned iface_index)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_leavegroup6</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaf54873a5fed045c9eff1200ebb368266</anchor>
+ <arglist>(tnet_fd_t fd, const char *multiaddr, unsigned iface_index)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_resolve</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga903b843f79e03448a90d70bdd92a4779</anchor>
+ <arglist>(const char *fqdn, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t *out_ip, tnet_port_t *out_port)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockaddrinfo_init</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>ad61bbea344fdf1113ca96aa8b4d03ecb</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *ai_addr, int *ai_family, int *ai_socktype, int *ai_protocol)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockaddr_init</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga0449294a58b8db4f81d835af2a535b90</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_init</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>adeb40eb2cb1616168082403075e13d51</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type, tnet_fd_t *fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_set_mode</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gab9616a14cc2c468ad99b510e276abac0</anchor>
+ <arglist>(tnet_fd_t fd, int nonBlocking)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_sendto</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga92fcf0392c9a93e2e578578479d4f35e</anchor>
+ <arglist>(tnet_fd_t fd, const struct sockaddr *to, const void *buf, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_recvfrom</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gabbf0cddd16af300a66d0859ed79b3cda</anchor>
+ <arglist>(tnet_fd_t fd, void *buf, tsk_size_t size, int flags, struct sockaddr *from)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tsk_size_t</type>
+ <name>tnet_sockfd_send</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga93356b04edf02a163bfaa421676f1efc</anchor>
+ <arglist>(tnet_fd_t fd, const void *buf, tsk_size_t size, int flags)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_recv</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaba9d8246797b995ecfb81f42f1bd1b96</anchor>
+ <arglist>(tnet_fd_t fd, void *buf, tsk_size_t size, int flags)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_connectto</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gafe03cf813e644a3d2cd2de8666d7f9c8</anchor>
+ <arglist>(tnet_fd_t fd, const struct sockaddr_storage *to)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_listen</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga92a295abbf85a361ee5c609994e21f05</anchor>
+ <arglist>(tnet_fd_t fd, int backlog)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API tnet_fd_t</type>
+ <name>tnet_sockfd_accept</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gae4350aa61a296325ce5dfc34fae616f8</anchor>
+ <arglist>(tnet_fd_t fd, struct sockaddr *addr, socklen_t *addrlen)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_close</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gad13808723477879ca310a70c527d850a</anchor>
+ <arglist>(tnet_fd_t *fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>TINYNET_API int</type>
+ <name>tnet_sockfd_shutdown</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaba68ca319965780023e3209dae7167fa</anchor>
+ <arglist>(tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_interface_t *</type>
+ <name>tnet_interface_create</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga519d8f6f2415bdf328e364f61bb47a39</anchor>
+ <arglist>(const char *description, const void *mac_address, tsk_size_t mac_address_length)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_address_t *</type>
+ <name>tnet_address_create</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga3e826cd2939bd297a73802b860262003</anchor>
+ <arglist>(const char *ip)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_interface_def_t</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>aa481fcf4bb5fab0c6027398b3910e409</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_address_def_t</name>
+ <anchorfile>tnet__utils_8h.html</anchorfile>
+ <anchor>acc7cf74fd6b2d76973dd6dad9cfabe33</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_turn.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/turn/</path>
+ <filename>tnet__turn_8c</filename>
+ <includes id="tnet__turn_8h" name="tnet_turn.h" local="yes" imported="no">tnet_turn.h</includes>
+ <includes id="tnet__turn__message_8h" name="tnet_turn_message.h" local="yes" imported="no">tnet_turn_message.h</includes>
+ <includes id="tnet__nat_8h" name="tnet_nat.h" local="yes" imported="no">../tnet_nat.h</includes>
+ <includes id="tnet__utils_8h" name="tnet_utils.h" local="yes" imported="no">../tnet_utils.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="typedef">
+ <type>tnet_stun_request_t *(*</type>
+ <name>tnet_turn_create_request_func</name>
+ <anchorfile>tnet__turn_8c.html</anchorfile>
+ <anchor>a381f4d2195b9e8be75743e8e5561cc92</anchor>
+ <arglist>)(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_channel_binding_t *</type>
+ <name>tnet_turn_channel_binding_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga103e23a60bb64dd069e6ab091784a6d4</anchor>
+ <arglist>(const tnet_turn_allocation_t *allocation)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_permission_t *</type>
+ <name>tnet_turn_permission_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8b42fc6a1e3f09cef7c7bf7c681a8218</anchor>
+ <arglist>(uint32_t timeout)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_allocation_t *</type>
+ <name>tnet_turn_allocation_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8ab0618c59d331267df779a881eb5bab</anchor>
+ <arglist>(tnet_fd_t fd, tnet_socket_type_t socket_type, const char *server_address, tnet_port_t server_port, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaddc8b26510c425a60140d25f131dcb85</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, tnet_stun_message_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_allocate</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gae1e001971df0be2311a06976e2f33201</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_refresh</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga2fde61ef85bcab916a3c9ce62789bd7e</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_unallocate</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga54c0fc2d0586f3160ab4f804c8a3950e</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_channel_bind</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gacca17b6face01e3f046e75f0624545eb</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_channel_refresh</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga86f4cd5cd926f84b75a3f8c86bcc348f</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_sendindication</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga346d00b42c27cb7f9a367d790137a351</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_permission</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gad8ed3de2531edf3185d41109d9411f2b</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_send_request</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaae576cf98cdc0ef40b0b3361327ad9cf</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, tnet_turn_create_request_func funcptr,...)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_allocation_id_t</type>
+ <name>tnet_turn_allocate</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gad66c1ecb8963678e0d8451fef43eafd0</anchor>
+ <arglist>(const tnet_nat_context_t *nat_context, const tnet_fd_t localFD, tnet_socket_type_t socket_type)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_allocation_refresh</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8f8e9c71f4fcbddc9a95e7cf0ce333a6</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, tnet_turn_allocation_t *allocation)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_unallocate</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gadfec48a9b5519234d73373a46b24606e</anchor>
+ <arglist>(const tnet_nat_context_t *nat_context, tnet_turn_allocation_t *allocation)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_channel_binding_id_t</type>
+ <name>tnet_turn_channel_bind</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga3e6e2ae486927450c8a32d3000dd0e85</anchor>
+ <arglist>(const tnet_nat_context_t *nat_context, tnet_turn_allocation_t *allocation, struct sockaddr_storage *peer)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_channel_refresh</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga39d90117f000959af24720570c240b75</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, const tnet_turn_channel_binding_t *channel_bind)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_channel_senddata</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8623d3c7fec8d357ad29f76633643109</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, const tnet_turn_channel_binding_t *channel_bind, const void *data, tsk_size_t size, int indication)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_add_permission</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gad49bc0f0bdd9832cf210825cc0b2156d</anchor>
+ <arglist>(const tnet_nat_context_t *nat_context, tnet_turn_allocation_t *allocation, const char *ipaddress, uint32_t timeout)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_channel_binding_def_t</name>
+ <anchorfile>tnet__turn_8c.html</anchorfile>
+ <anchor>a8c96cc1e81b39329d57e913cf3a22ab7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_permission_def_t</name>
+ <anchorfile>tnet__turn_8c.html</anchorfile>
+ <anchor>ac2c37805caacd556fb6b9e32b817e635</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_allocation_def_t</name>
+ <anchorfile>tnet__turn_8c.html</anchorfile>
+ <anchor>a9edbc36c8c4f6a56c71a5a00e98f9719</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_turn.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/turn/</path>
+ <filename>tnet__turn_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__turn__attribute_8h" name="tnet_turn_attribute.h" local="yes" imported="no">turn/tnet_turn_attribute.h</includes>
+ <includes id="tnet__proto_8h" name="tnet_proto.h" local="yes" imported="no">tnet_proto.h</includes>
+ <includes id="tnet__socket_8h" name="tnet_socket.h" local="yes" imported="no">tnet_socket.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">tnet_types.h</includes>
+ <class kind="struct">tnet_turn_permission_s</class>
+ <class kind="struct">tnet_turn_channel_binding_s</class>
+ <class kind="struct">tnet_turn_allocation_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TURN_PERMISSION_TIMEOUT_DEFAULT</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gae355f01c55abfcddc5e24b59acc170f6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TURN_CHANBIND_TIMEOUT_DEFAULT</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8aa082bcb28e67d8ec00e95b2fe5406f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TURN_INVALID_ALLOCATION_ID</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a52d97a7fd715a0dc770ad8afe885e50f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TURN_IS_VALID_ALLOCATION_ID</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a84362f7b61f67dc1f3a2543078e74bdd</anchor>
+ <arglist>(id)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TURN_INVALID_CHANNEL_BINDING_ID</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a23d5f1efb08ac449cc9e3d1ef859711e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TURN_IS_VALID_CHANNEL_BINDING_ID</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a491748f8fbd7476bbd33b4ba678dc0de</anchor>
+ <arglist>(id)</arglist>
+ </member>
+ <member kind="typedef">
+ <type>uint64_t</type>
+ <name>tnet_turn_allocation_id_t</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a78fc33b60d08b8c6c4480d855f98051b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>uint16_t</type>
+ <name>tnet_turn_channel_binding_id_t</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a613a5cdd5a850369c7b547934ae6c544</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_permission_s</type>
+ <name>tnet_turn_permission_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga022e47cd11dd0cd6b5985948e4f47421</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_turn_permissions_L_t</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>ae6574d0d25b43a7f1655d073c086d9d5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_channel_binding_s</type>
+ <name>tnet_turn_channel_binding_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga869e95eb9bf494895d66ad7a68f39cd1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_turn_channel_bindings_L_t</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a08a04f2fc0fd1f5db142d37ee61ffff8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_allocation_s</type>
+ <name>tnet_turn_allocation_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga4962ff19fd67702f01a1b1c107b19a56</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_turn_allocations_L_t</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>af966c78dcc79a47d86636c5710180663</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_allocation_id_t</type>
+ <name>tnet_turn_allocate</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a06d72656df436b315bbab5299e7947f1</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, const tnet_fd_t localFD, tnet_socket_type_t socket_type)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_allocation_refresh</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8f8e9c71f4fcbddc9a95e7cf0ce333a6</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, tnet_turn_allocation_t *allocation)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_unallocate</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>ab7b1b333af35a2367821c41793d745eb</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, tnet_turn_allocation_t *allocation)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_channel_binding_id_t</type>
+ <name>tnet_turn_channel_bind</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>aca13f95e34db4a637194a013b7ef594c</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, tnet_turn_allocation_t *allocation, struct sockaddr_storage *peer)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_channel_refresh</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga39d90117f000959af24720570c240b75</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, const tnet_turn_channel_binding_t *channel_bind)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_channel_senddata</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8623d3c7fec8d357ad29f76633643109</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, const tnet_turn_channel_binding_t *channel_bind, const void *data, tsk_size_t size, int indication)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_add_permission</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a41d5b5a2d4e282954b8503a1dcf14ba8</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, tnet_turn_allocation_t *allocation, const char *ipaddress, uint32_t timeout)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_permission_def_t</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a82139781df85506bc0fafe0f03f3e215</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_channel_binding_def_t</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>ae45bdb387bc5636788b75b2f8e7670af</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_allocation_def_t</name>
+ <anchorfile>tnet__turn_8h.html</anchorfile>
+ <anchor>a9f3b2fc224b7da612fef43c5df6ecee4</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_turn_attribute.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/turn/</path>
+ <filename>tnet__turn__attribute_8c</filename>
+ <includes id="tnet__turn__attribute_8h" name="tnet_turn_attribute.h" local="yes" imported="no">tnet_turn_attribute.h</includes>
+ <includes id="tnet__stun_8h" name="tnet_stun.h" local="yes" imported="no">../stun/tnet_stun.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_turn_attribute_channelnum_t *</type>
+ <name>tnet_turn_attribute_channelnum_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga407a64bdadf74e0cc58808f2f16de2fd</anchor>
+ <arglist>(uint16_t number)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_lifetime_t *</type>
+ <name>tnet_turn_attribute_lifetime_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga97892194ee263338e36c11d02d3c5ea2</anchor>
+ <arglist>(uint32_t lifetime)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_xpeer_addr_t *</type>
+ <name>tnet_turn_attribute_xpeer_addr_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaf66bebd5bd8319c454a450dc092973c5</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_xpeer_addr_t *</type>
+ <name>tnet_turn_attribute_xpeer_addr_create_null</name>
+ <anchorfile>tnet__turn__attribute_8c.html</anchorfile>
+ <anchor>afebd53010c1edb07cbe663cee6aaaf50</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_data_t *</type>
+ <name>tnet_turn_attribute_data_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga6e749efbc0e6c2d181b7b5572dd4a84a</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_xrelayed_addr_t *</type>
+ <name>tnet_turn_attribute_xrelayed_addr_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga27dd53bb4f5afd8fbe1b3c6450764d68</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_even_port_t *</type>
+ <name>tnet_turn_attribute_even_port_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga9201f3b08080e3d9d73d91cce22fdb6b</anchor>
+ <arglist>(unsigned R)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_reqtrans_t *</type>
+ <name>tnet_turn_attribute_reqtrans_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga0f8e1e1c00b3c62c9c451ad2dbf8419e</anchor>
+ <arglist>(tnet_proto_t protocol)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_dontfrag_t *</type>
+ <name>tnet_turn_attribute_dontfrag_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gab1baec0bd9b214f816737ccaf36846a7</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_restoken_t *</type>
+ <name>tnet_turn_attribute_restoken_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga498409f84c06d567eeeeb913b01117c8</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_t *</type>
+ <name>tnet_turn_attribute_deserialize</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gae0fac81dd69579c064501d497cd03ea8</anchor>
+ <arglist>(tnet_stun_attribute_type_t type, uint16_t length, const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_attribute_serialize</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga5c64288790f379c04d8aae14117e305c</anchor>
+ <arglist>(const tnet_stun_attribute_t *attribute, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_channelnum_def_t</name>
+ <anchorfile>tnet__turn__attribute_8c.html</anchorfile>
+ <anchor>a72f2fd30ca18baf219d74649601c1aad</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_lifetime_def_t</name>
+ <anchorfile>tnet__turn__attribute_8c.html</anchorfile>
+ <anchor>a60a2ffe2a549923f8a5ea6c778005fa8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_xpeer_addr_def_t</name>
+ <anchorfile>tnet__turn__attribute_8c.html</anchorfile>
+ <anchor>a99670a5af5f3a8ed7fd4efad17408487</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_data_def_t</name>
+ <anchorfile>tnet__turn__attribute_8c.html</anchorfile>
+ <anchor>a4aabd9e2dbe97cb3be22393bfd7a5c22</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_xrelayed_addr_def_t</name>
+ <anchorfile>tnet__turn__attribute_8c.html</anchorfile>
+ <anchor>a79af40ee574c272240e82525ffe3ad27</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_even_port_def_t</name>
+ <anchorfile>tnet__turn__attribute_8c.html</anchorfile>
+ <anchor>a048a8a7f4c325d410b81ff93868f91a7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_reqtrans_def_t</name>
+ <anchorfile>tnet__turn__attribute_8c.html</anchorfile>
+ <anchor>ad5b4ff0b5c890a8d80ebd7488980f6a3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_dontfrag_def_t</name>
+ <anchorfile>tnet__turn__attribute_8c.html</anchorfile>
+ <anchor>a59bb091518a3d8acb50372f498441daf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_restoken_def_t</name>
+ <anchorfile>tnet__turn__attribute_8c.html</anchorfile>
+ <anchor>a28eb707dbdbb91a8a63f112d6046d27c</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_turn_attribute.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/turn/</path>
+ <filename>tnet__turn__attribute_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">tinynet_config.h</includes>
+ <includes id="tnet__proto_8h" name="tnet_proto.h" local="yes" imported="no">tnet_proto.h</includes>
+ <includes id="tnet__stun__attribute_8h" name="tnet_stun_attribute.h" local="yes" imported="no">stun/tnet_stun_attribute.h</includes>
+ <class kind="struct">tnet_turn_attribute_channelnum_s</class>
+ <class kind="struct">tnet_turn_attribute_lifetime_s</class>
+ <class kind="struct">tnet_turn_attribute_xpeer_addr_s</class>
+ <class kind="struct">tnet_turn_attribute_data_s</class>
+ <class kind="struct">tnet_turn_attribute_xrelayed_addr_s</class>
+ <class kind="struct">tnet_turn_attribute_even_port_s</class>
+ <class kind="struct">tnet_turn_attribute_reqtrans_s</class>
+ <class kind="struct">tnet_turn_attribute_dontfrag_s</class>
+ <class kind="struct">tnet_turn_attribute_restoken_s</class>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_channelnum_s</type>
+ <name>tnet_turn_attribute_channelnum_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaa77bcb197c9e99794d67fd934d8c50c1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_lifetime_s</type>
+ <name>tnet_turn_attribute_lifetime_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga26a916f263289acaad0a56b7e374d028</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_xpeer_addr_s</type>
+ <name>tnet_turn_attribute_xpeer_addr_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaa7fa88cb2c5f7269b94a916b66083235</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_data_s</type>
+ <name>tnet_turn_attribute_data_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaaeab89d23a21fcfdaec9920fea7af597</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_xrelayed_addr_s</type>
+ <name>tnet_turn_attribute_xrelayed_addr_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga07d7abdfc37b58ca81964c22a5012e41</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_even_port_s</type>
+ <name>tnet_turn_attribute_even_port_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaa895b29c22d94e8cfcad5530a7d3264b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_reqtrans_s</type>
+ <name>tnet_turn_attribute_reqtrans_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga2ca2caa07d491a0d562e5b2e456d8f59</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_dontfrag_s</type>
+ <name>tnet_turn_attribute_dontfrag_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gab703b2d48941e0a376c5c5d82d0c2b83</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_restoken_s</type>
+ <name>tnet_turn_attribute_restoken_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga981d08f23d6a6c2f660e0b8631703093</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_t *</type>
+ <name>tnet_turn_attribute_deserialize</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gae0fac81dd69579c064501d497cd03ea8</anchor>
+ <arglist>(tnet_stun_attribute_type_t type, uint16_t length, const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_attribute_serialize</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga5c64288790f379c04d8aae14117e305c</anchor>
+ <arglist>(const tnet_stun_attribute_t *attribute, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_channelnum_t *</type>
+ <name>tnet_turn_attribute_channelnum_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga407a64bdadf74e0cc58808f2f16de2fd</anchor>
+ <arglist>(uint16_t number)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_lifetime_t *</type>
+ <name>tnet_turn_attribute_lifetime_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga97892194ee263338e36c11d02d3c5ea2</anchor>
+ <arglist>(uint32_t lifetime)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_xpeer_addr_t *</type>
+ <name>tnet_turn_attribute_xpeer_addr_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaf66bebd5bd8319c454a450dc092973c5</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_xpeer_addr_t *</type>
+ <name>tnet_turn_attribute_xpeer_addr_create_null</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>afebd53010c1edb07cbe663cee6aaaf50</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_data_t *</type>
+ <name>tnet_turn_attribute_data_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga6e749efbc0e6c2d181b7b5572dd4a84a</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_xrelayed_addr_t *</type>
+ <name>tnet_turn_attribute_xrelayed_addr_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga27dd53bb4f5afd8fbe1b3c6450764d68</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_even_port_t *</type>
+ <name>tnet_turn_attribute_even_port_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga9201f3b08080e3d9d73d91cce22fdb6b</anchor>
+ <arglist>(unsigned R)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_reqtrans_t *</type>
+ <name>tnet_turn_attribute_reqtrans_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga0f8e1e1c00b3c62c9c451ad2dbf8419e</anchor>
+ <arglist>(tnet_proto_t protocol)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_dontfrag_t *</type>
+ <name>tnet_turn_attribute_dontfrag_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gab1baec0bd9b214f816737ccaf36846a7</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_restoken_t *</type>
+ <name>tnet_turn_attribute_restoken_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga498409f84c06d567eeeeb913b01117c8</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TNET_BEGIN_DECLS typedef tnet_stun_attribute_t</type>
+ <name>tnet_turn_attribute_t</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>a00de15de99bdb6cce62f1ae7e326ff33</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_channelnum_def_t</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>aa9ccbc071dd9dc40b459e98e329a7b7f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_lifetime_def_t</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>ab6683e297789efe2ecb14d7fa617ced3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_xpeer_addr_def_t</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>a18c5987c8947a764223d1c6479aed130</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_data_def_t</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>aa8268a52ec6ea4183cb6cbcc4092a2d6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_xrelayed_addr_def_t</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>a695a13f8c65383eb1fda5d1e0e086cc4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_even_port_def_t</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>af8e79d87fc8a281fe70a27b8e4cf6b21</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_reqtrans_def_t</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>ace9cf4c1412342af44a6c01127c3c22f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_dontfrag_def_t</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>aa25f381fb1d4df9a64231c74163e9ec9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_attribute_restoken_def_t</name>
+ <anchorfile>tnet__turn__attribute_8h.html</anchorfile>
+ <anchor>a1d2d08c197e85e06c7f3f1abd75b0140</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_turn_message.c</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/turn/</path>
+ <filename>tnet__turn__message_8c</filename>
+ <includes id="tnet__turn__message_8h" name="tnet_turn_message.h" local="yes" imported="no">tnet_turn_message.h</includes>
+ <includes id="tnet__types_8h" name="tnet_types.h" local="yes" imported="no">../tnet_types.h</includes>
+ <includes id="tnet__endianness_8h" name="tnet_endianness.h" local="yes" imported="no">../tnet_endianness.h</includes>
+ <member kind="function">
+ <type>tnet_turn_channel_data_t *</type>
+ <name>tnet_turn_channel_data_create</name>
+ <anchorfile>tnet__turn__message_8c.html</anchorfile>
+ <anchor>aea95662fe6dbd4eca6e02d1a05ef42b9</anchor>
+ <arglist>(uint16_t number, uint16_t length, const void *data)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_channel_data_t *</type>
+ <name>tnet_turn_channel_data_create_null</name>
+ <anchorfile>tnet__turn__message_8c.html</anchorfile>
+ <anchor>aed557f9b1a06efc770b67fe6633b4373</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_turn_channel_data_serialize</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga00439f15cae25f78c4fd515c2ad689fc</anchor>
+ <arglist>(const tnet_turn_channel_data_t *message)</arglist>
+ </member>
+ <member kind="variable">
+ <type>const tsk_object_def_t *</type>
+ <name>tnet_turn_channel_data_def_t</name>
+ <anchorfile>tnet__turn__message_8c.html</anchorfile>
+ <anchor>ac5ac4021323667d38b4d942a391da23c</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>tnet_turn_message.h</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/turn/</path>
+ <filename>tnet__turn__message_8h</filename>
+ <includes id="tinynet__config_8h" name="tinynet_config.h" local="yes" imported="no">../tinynet_config.h</includes>
+ <class kind="struct">tnet_turn_channel_data_s</class>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_turn_channel_data_s</type>
+ <name>tnet_turn_channel_data_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga4878f9790955d14d532e4de51ac0fa5f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_turn_channel_data_serialize</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga00439f15cae25f78c4fd515c2ad689fc</anchor>
+ <arglist>(const tnet_turn_channel_data_t *message)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_channel_data_t *</type>
+ <name>tnet_turn_channel_data_create</name>
+ <anchorfile>tnet__turn__message_8h.html</anchorfile>
+ <anchor>aea95662fe6dbd4eca6e02d1a05ef42b9</anchor>
+ <arglist>(uint16_t number, uint16_t length, const void *data)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_channel_data_t *</type>
+ <name>tnet_turn_channel_data_create_null</name>
+ <anchorfile>tnet__turn__message_8h.html</anchorfile>
+ <anchor>aed557f9b1a06efc770b67fe6633b4373</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="variable">
+ <type>TINYNET_GEXTERN const tsk_object_def_t *</type>
+ <name>tnet_turn_channel_data_def_t</name>
+ <anchorfile>tnet__turn__message_8h.html</anchorfile>
+ <anchor>a52e135f0633a3a35dc8726b093b86ef9</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="group">
+ <name>tnet_dhcp_group</name>
+ <title>DHCPv4/BOOTP (RFC 2131) implementation.</title>
+ <filename>group__tnet__dhcp__group.html</filename>
+ <class kind="struct">tnet_dhcp_params_s</class>
+ <class kind="struct">tnet_dhcp_ctx_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_TIMEOUT_DEFAULT</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga4c4d364928ec9c9b7c2dbc6d59187b94</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_CLIENT_PORT</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga40d19eada507a56dd275125e3b1c195c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_SERVER_PORT</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>gae5229a21da05427c690040fa34a6a2b3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_VENDOR_ID_DEFAULT</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga68fdef222cf61845b6d961766b4cf276</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_MAX_CODES</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga2e7d7c17df6e0c697014a20ab344d1a8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DHCP_MAX_MSG_SIZE</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga9489b2e11946fde982adc9f88a148e5c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp_params_s</type>
+ <name>tnet_dhcp_params_t</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga6fc1dfe6651b6c630b32fb6744a269e9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_dhcp_ctx_s</type>
+ <name>tnet_dhcp_ctx_t</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>gab40673583cd866001d0afc7db3e01e59</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_ctx_t *</type>
+ <name>tnet_dhcp_ctx_create</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga4047baa7341d04b728d5884460214802</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_params_t *</type>
+ <name>tnet_dhcp_params_create</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga7d73362e75ec846e6ce440ba9178069a</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_reply_t *</type>
+ <name>tnet_dhcp_send_request</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>gafd37386ea787357f72a4c71f8f66df4f</anchor>
+ <arglist>(tnet_dhcp_ctx_t *ctx, tnet_dhcp_request_t *request)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp_reply_t *</type>
+ <name>tnet_dhcp_query</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga66e173bcf5fd24b06a204be44312c56a</anchor>
+ <arglist>(tnet_dhcp_ctx_t *ctx, tnet_dhcp_message_type_t type, tnet_dhcp_params_t *params)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dhcp_params_add_code</name>
+ <anchorfile>group__tnet__dhcp__group.html</anchorfile>
+ <anchor>ga9fb8994c0bb692b29ccd0454cc592bc5</anchor>
+ <arglist>(tnet_dhcp_params_t *params, tnet_dhcp_option_code_t code)</arglist>
+ </member>
+ </compound>
+ <compound kind="group">
+ <name>tnet_dhcp6_group</name>
+ <title>DHCPv6 (RFC 3315) implementation.</title>
+ <filename>group__tnet__dhcp6__group.html</filename>
+ <member kind="function">
+ <type>tnet_dhcp6_reply_t *</type>
+ <name>tnet_dhcp6_send_request</name>
+ <anchorfile>group__tnet__dhcp6__group.html</anchorfile>
+ <anchor>gadac4a203c542c67bcd608974944ade8d</anchor>
+ <arglist>(const tnet_dhcp6_ctx_t *ctx, tnet_dhcp6_request_t *request)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dhcp6_reply_t *</type>
+ <name>tnet_dhcp6_requestinfo</name>
+ <anchorfile>group__tnet__dhcp6__group.html</anchorfile>
+ <anchor>gac8dd99f4e54866bbdf190ce5061b5b3a</anchor>
+ <arglist>(const tnet_dhcp6_ctx_t *ctx, const tnet_dhcp6_option_orequest_t *orequest)</arglist>
+ </member>
+ </compound>
+ <compound kind="group">
+ <name>tnet_dns_group</name>
+ <title>DNS utility functions (RFCS [1034 1035] [3401 3402 3403 3404]).</title>
+ <filename>group__tnet__dns__group.html</filename>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_CACHE_TTL</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gad0036c81833a0d67783075346183f741</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_TIMEOUT_DEFAULT</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga27019bac31c0cd87fcf5f1d440d44db2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_DGRAM_SIZE_DEFAULT</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga3f0a0842a1099131e50c4ce1358a8d66</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_SERVER_PORT_DEFAULT</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga3687b2e64d73b85594bd93a79df252af</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_MESSAGE_IS_RESPONSE</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga2a5cf37ea80a5c81714042074eac92bf</anchor>
+ <arglist>(message)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_MESSAGE_IS_QUERY</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaf24bf109d5da866b600989d53c24f2aa</anchor>
+ <arglist>(message)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_RESPONSE_IS_SUCCESS</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaefa196185f91151ec1b70542d73f230b</anchor>
+ <arglist>(response)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_DNS_RESPONSE_IS_ERROR</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gab7b1d2b4373729da855fad1816ef9e81</anchor>
+ <arglist>(response)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_ctx_t *</type>
+ <name>tnet_dns_ctx_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga080c974f8f6bdb3779bfae98956e9821</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_cache_entry_t *</type>
+ <name>tnet_dns_cache_entry_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga130888ddea8e08e520a2ffd02278d90d</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t *answer)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_cache_clear</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga4908f53f564e46f39472e1dc825aa3ce</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_response_t *</type>
+ <name>tnet_dns_resolve</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaaaee535d51058d67d9f170239de354b3</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_response_t *</type>
+ <name>tnet_dns_enum</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaf08d4dbbaf1025a17613bd553bf4db78</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *e164num, const char *domain)</arglist>
+ </member>
+ <member kind="function">
+ <type>char *</type>
+ <name>tnet_dns_enum_2</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga1aa07c721d9e2e7bac6eea9f44a515c8</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *service, const char *e164num, const char *domain)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_query_srv</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gab4b9b4f145decf0d2886c8a4ea25a313</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *service, char **hostname, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_query_naptr_srv</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga0c2c6cdb03f205b6ce16af9398d91730</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *domain, const char *service, char **hostname, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_dns_add_server</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga9d617f0cf0f0dc70e4a3bca53ab23824</anchor>
+ <arglist>(tnet_dns_ctx_t *ctx, const char *host)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_message_t *</type>
+ <name>tnet_dns_message_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga98138daa781d9c12a4ba43f3371d0895</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tsk_bool_t isquery)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_message_t *</type>
+ <name>tnet_dns_message_create_null</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga353b8a830ee67c2a2d2a6e810f081ea9</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_response_t *</type>
+ <name>tnet_dns_response_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gaca11f63942b2ed04516a0d2323c75e7f</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_query_t *</type>
+ <name>tnet_dns_query_create</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>gac97c055c0a0a84882eb586feb22ef097</anchor>
+ <arglist>(const char *qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_dns_message_serialize</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga98f52e21a3d361e2a837993c31756871</anchor>
+ <arglist>(const tnet_dns_message_t *message)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_dns_message_t *</type>
+ <name>tnet_dns_message_deserialize</name>
+ <anchorfile>group__tnet__dns__group.html</anchorfile>
+ <anchor>ga72d0a558aa990326e3724bd06260ac65</anchor>
+ <arglist>(const uint8_t *data, tsk_size_t size)</arglist>
+ </member>
+ </compound>
+ <compound kind="group">
+ <name>tnet_stun_group</name>
+ <title>STUN2 (RFC 5389) implementation.</title>
+ <filename>group__tnet__stun__group.html</filename>
+ <class kind="struct">tnet_stun_binding_s</class>
+ <class kind="struct">tnet_stun_attribute_s</class>
+ <class kind="struct">tnet_stun_attribute_mapped_addr_s</class>
+ <class kind="struct">tnet_stun_attribute_xmapped_addr_s</class>
+ <class kind="struct">tnet_stun_attribute_username_s</class>
+ <class kind="struct">tnet_stun_attribute_integrity_s</class>
+ <class kind="struct">tnet_stun_attribute_fingerprint_s</class>
+ <class kind="struct">tnet_stun_attribute_errorcode_s</class>
+ <class kind="struct">tnet_stun_attribute_realm_s</class>
+ <class kind="struct">tnet_stun_attribute_nonce_s</class>
+ <class kind="struct">tnet_stun_attribute_unknowns_s</class>
+ <class kind="struct">tnet_stun_attribute_software_s</class>
+ <class kind="struct">tnet_stun_attribute_altserver_s</class>
+ <class kind="struct">tnet_stun_attribute_ice_priority_s</class>
+ <class kind="struct">tnet_stun_attribute_ice_use_candidate_s</class>
+ <class kind="struct">tnet_stun_attribute_ice_controlled_s</class>
+ <class kind="struct">tnet_stun_attribute_ice_controlling_s</class>
+ <class kind="struct">tnet_stun_message_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_INVALID_BINDING_ID</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaeb338f5c8a9b3ac08bba78293fdc22d4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_IS_VALID_BINDING_ID</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga809cd1386eaa84094e78ef17a414ad7d</anchor>
+ <arglist>(id)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_TCP_UDP_DEFAULT_PORT</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga840d6af2bf3bd3a96d120c942abefd7a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_TLS_DEFAULT_PORT</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab0ae6bc64ad691f9bc5bd2b4c88c4569</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_MAGIC_COOKIE</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gac5e54e4b4576b54b53d2f4242f3e30de</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_HEADER_SIZE</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga1df2b74747811b1bbdad28b18e0d80c3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_ATTRIBUTE</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaeec0275bf11e81b2b89c149df5194c51</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_MESSAGE_IS_REQUEST</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga50742ed21d77367f7d6d0b1ece487d94</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_MESSAGE_IS_INDICATION</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga05a95d304163ba125defae8444a28f73</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_RESPONSE_IS_SUCCESS</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga98049d686a5db4369a7554a77bf26838</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_RESPONSE_IS_ERROR</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga10bdb77a5f51b4670be89302eb445974</anchor>
+ <arglist>(self)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_IS_STUN2_MSG</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3e9c76b717211f3d8c27d624a07e2353</anchor>
+ <arglist>(PU8, SIZE)</arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_STUN_TRANSACID_SIZE</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaaa796e7b0e870b335336c50024ef5823</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_binding_s</type>
+ <name>tnet_stun_binding_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gabb378355a46b1aef733acdeef3a38368</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>tsk_list_t</type>
+ <name>tnet_stun_bindings_L_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga994b6db4d6ac6e78c4ece450f1d5edff</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_stun_addr_family_e</type>
+ <name>tnet_stun_addr_family_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7080ca2a8d2b45a22d21c522a2a5a28f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_stun_attribute_type_e</type>
+ <name>tnet_stun_attribute_type_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga2e77e50a4af676b754191403ae102933</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_s</type>
+ <name>tnet_stun_attribute_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3ce2a25dae1324a8dd545a68a2d8ccf3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_mapped_addr_s</type>
+ <name>tnet_stun_attribute_mapped_addr_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga6ef5c5c6d47376dc7cf7ac14b923ad26</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_xmapped_addr_s</type>
+ <name>tnet_stun_attribute_xmapped_addr_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8885759ce02dd0bebc0bee97ec48171c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_username_s</type>
+ <name>tnet_stun_attribute_username_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga33d875930c4e6213e7516e580a88eebb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_integrity_s</type>
+ <name>tnet_stun_attribute_integrity_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8b2b266a46e44c471708eca71ac8670a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_fingerprint_s</type>
+ <name>tnet_stun_attribute_fingerprint_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7ead14f441ddf014894c17fcef2feeaf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_errorcode_s</type>
+ <name>tnet_stun_attribute_errorcode_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga0e804aae488d73e576dd9c4453a93a04</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_realm_s</type>
+ <name>tnet_stun_attribute_realm_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaaf4ef4fa43bec46b6313c0c400d6c6ca</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_nonce_s</type>
+ <name>tnet_stun_attribute_nonce_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7e4d37384aa42524d68d8e9e0ddc9ea2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_unknowns_s</type>
+ <name>tnet_stun_attribute_unknowns_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab27dd830e06e223350a584c41383015d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_software_s</type>
+ <name>tnet_stun_attribute_software_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga5744df35d8bf1f1f366097f6a63f1177</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_altserver_s</type>
+ <name>tnet_stun_attribute_altserver_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga1912ae8bc9ea407a04f1d16aa570dbc9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_ice_priority_s</type>
+ <name>tnet_stun_attribute_ice_priority_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga782dcf37c6503a9287b479cef6fe0132</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_ice_use_candidate_s</type>
+ <name>tnet_stun_attribute_ice_use_candidate_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga47de3ced777b9c46f863e513b934ab23</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_ice_controlled_s</type>
+ <name>tnet_stun_attribute_ice_controlled_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab46c08e93d0c514a72fc8b3f73bc7a77</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_attribute_ice_controlling_s</type>
+ <name>tnet_stun_attribute_ice_controlling_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gac4832ed589696b4a9ef6274b96333adf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>uint8_t</type>
+ <name>tnet_stun_transacid_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaab3bfd494f75601a0f26177c6d851810</anchor>
+ <arglist>[TNET_STUN_TRANSACID_SIZE]</arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_stun_class_type_e</type>
+ <name>tnet_stun_class_type_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8db95f74a4953795bf182744e63eff78</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_stun_method_type_e</type>
+ <name>tnet_stun_method_type_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga145552721a7b4f524ceb40ac2da1038d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>enum tnet_stun_message_type_e</type>
+ <name>tnet_stun_message_type_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab3ed2f3313ef6914347c2e604d7cf104</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_stun_message_s</type>
+ <name>tnet_stun_message_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga4e9470802bdd2d8b0a1b90631369721e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_stun_addr_family_e</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3326fbcc063f264d3d359e922637e2e4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ipv4</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3326fbcc063f264d3d359e922637e2e4a5663f4b60301ed2f9e7823613407dbed</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ipv6</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3326fbcc063f264d3d359e922637e2e4a97e1e424d39a8af2791c1187090f111e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_stun_attribute_type_e</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab696586b61219965987af1e017e6ffa6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_reserved</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a5bf34ce06a004ad9f8db1dc687786273</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_mapped_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a9aadc5f8467c936cc7359889ba120e33</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_response_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a203b0a7edf4f8fb3381ac769595a2098</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_change_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6aeb35b7b83152b7a99bf46b4014928adc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_source_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a69f3448100d4f1a61536eb2c7315cd90</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_changed_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a0bd0d2c8f1d6ae85ffb58aeef4c01134</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_username</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a3247970572dad0c63e537b647dbd0861</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_password</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a432698b7b67cf13adf504f969abb60fd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_message_integrity</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ac20851e6e8fd2c479c0438b376987a85</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_error_code</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ab8571c9a5c334530ef9aa45adc7fd71e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_unknown_attributes</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a455d442e5c380953ff11c7e0d055f3ae</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_reflected_from</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ae129dfcf945fe995400dba3e8b9895c5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_realm</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a0d8e28c40313d6d3b397ac957714cfee</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_nonce</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ae5dda080590c37e95953334f715ed3ef</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_xor_mapped_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6af70dcad086bff5d4ee77f093941642d2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_software</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ad5a2f9a89fbc825142e4d754b51bc125</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_alternate_server</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a4f263d754aaccf30fd861a934dfc12ba</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_fingerprint</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6aac669613b66507fba6c08d23a4283bf2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_channel_number</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a7559421f1d46a400cdda94c32c3aff74</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_lifetime</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6aff4ed6f5e451f77b39d5113b9085493c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_reserved2</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a626c6684c81f69c1649e178cc9847069</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_xor_peer_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ae14d3b3903934eab51356ad28584fc66</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_data</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ab85dfed04ff37affea00d10a517c72dd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_xor_relayed_address</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ada0a3d93b81c32a3d0af2ed20efffe71</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_even_port</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6ac99da9ae2b9a6a885631e5e476293df2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_requested_transport</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a033a9a9cdad515c45291007be25dd028</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_dont_fragment</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a3f854135f19b767abc7e8031af6b5f88</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_reserved3</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a57c9e8d7229d0989d73a5efc2fef36e7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_reservation_token</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a88373f0f1635103b2091910a9584c58d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ice_priority</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a99410d8e75f7ab0d4421fe71634604bb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ice_use_candidate</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a275c187aabe3a9d9bdc32a180c39b1d2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ice_controlled</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a4cfd4eab6287ed2b1126e6ba40ac5d4a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_ice_controlling</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggab696586b61219965987af1e017e6ffa6a21100a7a716c88ed5b5544cdb28549aa</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_stun_class_type_e</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3faef946079e315842f5ad4d41aa0929</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_class_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3faef946079e315842f5ad4d41aa0929a4617c080243a43b3d8f93bdfcc3f0f4b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_class_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3faef946079e315842f5ad4d41aa0929a204a6136670e4ad622276ef22a2ae65e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_class_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3faef946079e315842f5ad4d41aa0929a0f27f07bfc9be6aa217799fa088cf059</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_class_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga3faef946079e315842f5ad4d41aa0929a271a1bc249f8bc1af5b9e6308b166232</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_stun_method_type_e</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga4701a0e3395592a6d6a742901212801c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_binding</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801cafd301f45e6297ffca65062c30b89ef53</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_allocate</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca166402bfafe37fa33b31f1466265798b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_refresh</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca6081fbd713a271d81264c919a589ce97</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_send</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca3c8e39a747df8f52dcc70d5d7db3e423</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_data</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca72ac38a767b77800980a5577dd13059c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_createpermission</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca45791d8de7420d9d3afccfc78ac8ba8b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_method_channelbind</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gga4701a0e3395592a6d6a742901212801ca9a883e8885d8eb35a93beccda692233c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumeration">
+ <type></type>
+ <name>tnet_stun_message_type_e</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gabf2f8d8b846fe491470941a7e237559c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_binding_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559caef49ee403fb2e849831649e4c09729d4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_binding_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca40f5bbd220cf9c1ec50654becc93c75f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_binding_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca45e30ced8713c5c159bb45641ce04e79</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_binding_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca9526f90725e2c9be01cd4ea2aa818e50</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_allocate_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cab3d8c425c241c43ab3bdbec7fdddc2dd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_allocate_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cadda6f40f23dc4bd53d1d6c068484ada0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_allocate_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559caf20455522d8e72c9e055b8ea5ef2dabb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_allocate_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cae4d21e386431edf815a9a652f3d745a5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_refresh_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca3f15b1671e604a2fb7a65401756dccc0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_refresh_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca5130e27fd810862da942fcde58eb0c42</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_refresh_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559caead4a26ba4d373a96e4dac68ff9fdb45</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_refresh_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca17067ce9dae33780b432c50b2a53130b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_send_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cac7424fdd7360f72326f8f9c74d36d15b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_data_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca66d958d23caaac30ab000f37c36a3406</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_createpermission_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559ca55ffb1e77c92edb303a51f7221049c66</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_createpermission_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cad1099efddc3ea3f8e91bd7953fef5c50</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_createpermission_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559caa804d83ad6928163af8e5b8c29c003dc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_createpermission_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cad3da1d3b613236f00e9747a3874eb3c8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_channelbind_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559caf9886f762e46af82fc8122ba35a95a8a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_channelbind_indication</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cae56d07904cc9d8091f32a6973258146f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_channelbind_success_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cafcb4db651d71fd5c21f7bbb2def064a1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="enumvalue">
+ <name>stun_channelbind_error_response</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ggabf2f8d8b846fe491470941a7e237559cab65200966087d7dd85dd17de30cde9ab</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_binding_t *</type>
+ <name>tnet_stun_binding_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga60801a4caec4d4335f0b4fea0e63025e</anchor>
+ <arglist>(tnet_fd_t fd, tnet_socket_type_t socket_type, const char *server_address, tnet_port_t server_port, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_message_t *</type>
+ <name>tnet_stun_create_request</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga481bcd3d5bfdfda6561227bfcf1fc359</anchor>
+ <arglist>(const tnet_stun_binding_t *binding)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_response_t *</type>
+ <name>tnet_stun_send_unreliably</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga36147911b3c99cbf897930c971608a5f</anchor>
+ <arglist>(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const tnet_stun_message_t *message, struct sockaddr *server)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_send_bind</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8151700d692ca34abf3cd42982723aa7</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_stun_binding_t *binding)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_binding_id_t</type>
+ <name>tnet_stun_bind</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gafad0d44c67c44e0cf91de149a32e8079</anchor>
+ <arglist>(const tnet_nat_context_t *nat_context, tnet_fd_t localFD)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_transacid_cmp</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gad2cd556a7d81575118646c3e3002af66</anchor>
+ <arglist>(const tnet_stun_transacid_t id1, const tnet_stun_transacid_t id2)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_t *</type>
+ <name>tnet_stun_attribute_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga9a8fea6f7fb4c6236bc4df85153d6af4</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_mapped_addr_t *</type>
+ <name>tnet_stun_attribute_mapped_address_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga28ffe32f830bbe0f5b32a207538eb8b6</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_xmapped_addr_t *</type>
+ <name>tnet_stun_attribute_xmapped_address_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gacd4af1df8c9e298a23d34df27e5dcc45</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_username_t *</type>
+ <name>tnet_stun_attribute_username_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab92c8f62b2d188c9ac1528aa03da4b7e</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_integrity_t *</type>
+ <name>tnet_stun_attribute_integrity_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga3c5f79313850ea8643132b093e11ef6a</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_fingerprint_t *</type>
+ <name>tnet_stun_attribute_fingerprint_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga2432db4c4bb63da2327bb357361eef21</anchor>
+ <arglist>(uint32_t fingerprint)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_errorcode_t *</type>
+ <name>tnet_stun_attribute_errorcode_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaa51e8bc565195298fb3de24070f5614a</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_realm_t *</type>
+ <name>tnet_stun_attribute_realm_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga2d7ab50986b3af03951358ec4c2cfa8b</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_nonce_t *</type>
+ <name>tnet_stun_attribute_nonce_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga0cf404a4977b95a47c252f8101b099ce</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_unknowns_t *</type>
+ <name>tnet_stun_attribute_unknowns_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8a497b2b11b1a776ec37170ee14b6ac2</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_software_t *</type>
+ <name>tnet_stun_attribute_software_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga719d8c3ac6588124533f03f70877e437</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_altserver_t *</type>
+ <name>tnet_stun_attribute_altserver_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga586636541b8ebb9ea46d4df39a448121</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_ice_priority_t *</type>
+ <name>tnet_stun_attribute_ice_priority_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7e2992cbcf5e4d93fce285c8fdad6018</anchor>
+ <arglist>(uint32_t value)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_ice_use_candidate_t *</type>
+ <name>tnet_stun_attribute_ice_use_candidate_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gafc6efba58197cb3d697502bbad7378cf</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_ice_controlled_t *</type>
+ <name>tnet_stun_attribute_ice_controlled_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaf2e4854c90f7c8c3abae9915e59ad12f</anchor>
+ <arglist>(uint64_t value)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_ice_controlling_t *</type>
+ <name>tnet_stun_attribute_ice_controlling_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga94da0e7a21d255c8647c190387229ba3</anchor>
+ <arglist>(uint64_t value)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_t *</type>
+ <name>tnet_stun_attribute_deserialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga642d9b382cea0cbbf0590b8b60be54c6</anchor>
+ <arglist>(const void *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_attribute_serialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gabb81a19c0eeb9f47f0b9599d65d61d6e</anchor>
+ <arglist>(const tnet_stun_attribute_t *attribute, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>void</type>
+ <name>tnet_stun_attribute_pad</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga9364909d8a9c38fa1be0dd48efa3fac3</anchor>
+ <arglist>(const tnet_stun_attribute_t *attribute, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_message_t *</type>
+ <name>tnet_stun_message_create</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaaf1892e2a30f8b85e4e5b47622a6b9f3</anchor>
+ <arglist>(const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_message_t *</type>
+ <name>tnet_stun_message_create_null</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga938bc40f8bb818f87c94eb42352cd0f3</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_stun_message_serialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaefd2306ef33e3611a98394e5b274a069</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_message_t *</type>
+ <name>tnet_stun_message_deserialize</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga0f5f3b814bb84f3cb62802b1d9af275e</anchor>
+ <arglist>(const uint8_t *data, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_stun_message_has_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga250b97b6a26f99f9d545533e20d29acb</anchor>
+ <arglist>(const tnet_stun_message_t *self, tnet_stun_attribute_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_message_add_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gacb982af5ead9faf9e85b4e2f69e05d47</anchor>
+ <arglist>(tnet_stun_message_t *self, tnet_stun_attribute_t **attribute)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_stun_message_remove_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga8c3cf4006d4c030e0114b8c00f2dc5ec</anchor>
+ <arglist>(tnet_stun_message_t *self, tnet_stun_attribute_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>const tnet_stun_attribute_t *</type>
+ <name>tnet_stun_message_get_attribute</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gaeac2966bdc80f798ec61f6f7ebfc6a95</anchor>
+ <arglist>(const tnet_stun_message_t *self, tnet_stun_attribute_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>short</type>
+ <name>tnet_stun_message_get_errorcode</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga7638d5816c344718874a113abd9739d5</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_stun_message_get_realm</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga6115407c7af73b3041c215ccd34e35b8</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>const char *</type>
+ <name>tnet_stun_message_get_nonce</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga5e068d5474bfbd73e8cece833deac6b2</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>int32_t</type>
+ <name>tnet_stun_message_get_lifetime</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga12380617e5a883d3c175216c48245839</anchor>
+ <arglist>(const tnet_stun_message_t *self)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_bool_t</type>
+ <name>tnet_stun_message_transac_id_equals</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>ga401b2a061923a11340da833dc248fa9d</anchor>
+ <arglist>(const tnet_stun_transacid_t id1, const tnet_stun_transacid_t id2)</arglist>
+ </member>
+ <member kind="variable">
+ <type>TNET_BEGIN_DECLS typedef uint64_t</type>
+ <name>tnet_stun_binding_id_t</name>
+ <anchorfile>group__tnet__stun__group.html</anchorfile>
+ <anchor>gab95871f186b8bf46b4630ab2ebb146aa</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="group">
+ <name>tnet_nat_group</name>
+ <title>NAT Traversal API (STUN, TURN and ICE).</title>
+ <filename>group__tnet__nat__group.html</filename>
+ <class kind="struct">tnet_nat_context_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_DEFAULT_RTO</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga25beb3cb889e80636f91ed1e316ef083</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_ICE_DEFAULT_RC</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gaf2d937114195afa44a46b88b898a781b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_NAT_DEFAULT_RTO</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga18cf72a341f3c785ab00a746286db1e6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_NAT_DEFAULT_RC</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga5e809d1461c049e1830e5d376a07bd11</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_NAT_TCP_UDP_DEFAULT_PORT</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga0a871f1c40c7acb827f0513958ec8b21</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_nat_context_s</type>
+ <name>tnet_nat_context_t</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga4d037b7a4416b7e876163d3c05256a1e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>void</type>
+ <name>tnet_nat_context_handle_t</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga82ef754b59414ada0129fa558e9f3ec2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_nat_context_handle_t *</type>
+ <name>tnet_nat_context_create</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga49c2521bd48d6df2ce3a46e066ebe874</anchor>
+ <arglist>(tnet_socket_type_t socket_type, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_set_server_address</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga60f64045a1a894a41afdb73a332f8732</anchor>
+ <arglist>(tnet_nat_context_handle_t *self, const char *server_address)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_set_server</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gadb5209238b5596dac88606e5130dc93f</anchor>
+ <arglist>(tnet_nat_context_handle_t *self, const char *server_address, tnet_port_t server_port)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_binding_id_t</type>
+ <name>tnet_nat_stun_bind</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gaedaee292e59564e952b1ddda3b82f0a6</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, const tnet_fd_t localFD)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_stun_get_reflexive_address</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga806a269daee5625262abe17c730d6bfc</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_stun_binding_id_t id, char **ipaddress, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_stun_unbind</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>gac7501503711b402a1863967000970e16</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_stun_binding_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_allocation_id_t</type>
+ <name>tnet_nat_turn_allocate</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga0388eae3c1cb2390070e49845a9e7a33</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, const tnet_fd_t localFD)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_get_reflexive_address</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga4417d9c60fcfae071ffee563b1e5f4dd</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id, char **ipaddress, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_allocation_refresh</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga6c0eb272fdaf34b696f40aa7f5279c24</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_unallocate</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga5ffc9393817f43bdd1331454a6f8af6e</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_channel_binding_id_t</type>
+ <name>tnet_nat_turn_channel_bind</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga2c1bed31feafaa25d30cf8cc92b0b9e5</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id, struct sockaddr_storage *peer)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_channel_refresh</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga4995c26dc8e520f2820924082b1c5193</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_channel_binding_id_t id)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_channel_send</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga69719fb972fa3ccf667dd3999c221e8c</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_channel_binding_id_t id, const void *data, tsk_size_t size, int indication)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_nat_turn_add_permission</name>
+ <anchorfile>group__tnet__nat__group.html</anchorfile>
+ <anchor>ga67181e6f65d829d44089841fd72429f0</anchor>
+ <arglist>(const tnet_nat_context_handle_t *self, tnet_turn_allocation_id_t id, const char *ipaddress, uint32_t timeout)</arglist>
+ </member>
+ </compound>
+ <compound kind="group">
+ <name>tnet_socket_group</name>
+ <title>Protocol agnostic socket</title>
+ <filename>group__tnet__socket__group.html</filename>
+ <member kind="function">
+ <type>tnet_socket_t *</type>
+ <name>tnet_socket_create_2</name>
+ <anchorfile>group__tnet__socket__group.html</anchorfile>
+ <anchor>gaa4d96c3d0bac908bd2d3413fbd19d30d</anchor>
+ <arglist>(const char *host, tnet_port_t port_, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_socket_t *</type>
+ <name>tnet_socket_create</name>
+ <anchorfile>group__tnet__socket__group.html</anchorfile>
+ <anchor>ga44cfc3407bc375c5b932bfe45a9de849</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type)</arglist>
+ </member>
+ </compound>
+ <compound kind="group">
+ <name>tnet_utils_group</name>
+ <title>Network utility functions.</title>
+ <filename>group__tnet__utils__group.html</filename>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_CONNECT_TIMEOUT</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga2d7e6e8cff043b7f3c0bda66a7a728bd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_interface_t *</type>
+ <name>tnet_interface_create</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga519d8f6f2415bdf328e364f61bb47a39</anchor>
+ <arglist>(const char *description, const void *mac_address, tsk_size_t mac_address_length)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_address_t *</type>
+ <name>tnet_address_create</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga3e826cd2939bd297a73802b860262003</anchor>
+ <arglist>(const char *ip)</arglist>
+ </member>
+ <member kind="function">
+ <type>void</type>
+ <name>tnet_getlasterror</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gac2b13fc342bfffa18868d8d91596961f</anchor>
+ <arglist>(tnet_error_t *error)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_geterrno</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaf5def7b9d46329d20e8939a98482603f</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_interfaces_L_t *</type>
+ <name>tnet_get_interfaces</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gad982a81d6170a3e4826180ff72efe5fe</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_addresses_L_t *</type>
+ <name>tnet_get_addresses</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga6c6add3dc5bdf1f3b9cddd4430254fc4</anchor>
+ <arglist>(tnet_family_t family, tsk_bool_t unicast, tsk_bool_t anycast, tsk_bool_t multicast, tsk_bool_t dnsserver, long if_index)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_getbestsource</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gac336e82f244c99e56b440b3b55c60c6a</anchor>
+ <arglist>(const char *destination, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t *source)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_getaddrinfo</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga36ace730e3924849994ea87548d495be</anchor>
+ <arglist>(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)</arglist>
+ </member>
+ <member kind="function">
+ <type>void</type>
+ <name>tnet_freeaddrinfo</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga18b2d2888f220d3117ee3b681c464922</anchor>
+ <arglist>(struct addrinfo *ai)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_getsockname</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaa1646c470ce392009805d7b46e5fe085</anchor>
+ <arglist>(tnet_fd_t fd, struct sockaddr_storage *result)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_socket_type_t</type>
+ <name>tnet_get_socket_type</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gac13e28b8f1c767306245bd3bf13f5e3c</anchor>
+ <arglist>(tnet_fd_t fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_family_t</type>
+ <name>tnet_get_family</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga00003bf6a8749b31d4b60b09cf5337a3</anchor>
+ <arglist>(const char *host, tnet_port_t port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_get_sockip_n_port</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga66eefd3c3bb0cc2c7a287374449b700e</anchor>
+ <arglist>(const struct sockaddr *addr, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_get_peerip_n_port</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga9a18f5ae763f323f38200e11b9ba369d</anchor>
+ <arglist>(tnet_fd_t localFD, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_get_ip_n_port</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga7feb0af8302b35bf835036ab7a48c4e9</anchor>
+ <arglist>(tnet_fd_t fd, tsk_bool_t getlocal, tnet_ip_t *ip, tnet_port_t *port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_getnameinfo</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga043fd7c4105a0d2014f3e0670b888d94</anchor>
+ <arglist>(const struct sockaddr *sa, socklen_t salen, char *node, socklen_t nodelen, char *service, socklen_t servicelen, int flags)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_gethostname</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga906ade6f28556babf47cb08dc947abd1</anchor>
+ <arglist>(tnet_host_t *result)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_waitUntil</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga3365d143e90fc4a1f83d330f489feb08</anchor>
+ <arglist>(tnet_fd_t fd, long timeout, tsk_bool_t writable)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_joingroup6</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga39276ddf27fe08518cf2431ae46a2045</anchor>
+ <arglist>(tnet_fd_t fd, const char *multiaddr, unsigned iface_index)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_leavegroup6</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaf54873a5fed045c9eff1200ebb368266</anchor>
+ <arglist>(tnet_fd_t fd, const char *multiaddr, unsigned iface_index)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_resolve</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga903b843f79e03448a90d70bdd92a4779</anchor>
+ <arglist>(const char *fqdn, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t *out_ip, tnet_port_t *out_port)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockaddrinfo_init</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaeb05ffebc3d308fd2ebb39de546c70a5</anchor>
+ <arglist>(const char *host, tnet_port_t port, enum tnet_socket_type_e type, struct sockaddr_storage *ai_addr, int *ai_family, int *ai_socktype, int *ai_protocol)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockaddr_init</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga0449294a58b8db4f81d835af2a535b90</anchor>
+ <arglist>(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *addr)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_init</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga02e3ba851395a9688b964cc228b732a8</anchor>
+ <arglist>(const char *host, tnet_port_t port, enum tnet_socket_type_e type, tnet_fd_t *fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_set_mode</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gab9616a14cc2c468ad99b510e276abac0</anchor>
+ <arglist>(tnet_fd_t fd, int nonBlocking)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_sendto</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga92fcf0392c9a93e2e578578479d4f35e</anchor>
+ <arglist>(tnet_fd_t fd, const struct sockaddr *to, const void *buf, tsk_size_t size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_recvfrom</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gabbf0cddd16af300a66d0859ed79b3cda</anchor>
+ <arglist>(tnet_fd_t fd, void *buf, tsk_size_t size, int flags, struct sockaddr *from)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_size_t</type>
+ <name>tnet_sockfd_send</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga93356b04edf02a163bfaa421676f1efc</anchor>
+ <arglist>(tnet_fd_t fd, const void *buf, tsk_size_t size, int flags)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_recv</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaba9d8246797b995ecfb81f42f1bd1b96</anchor>
+ <arglist>(tnet_fd_t fd, void *buf, tsk_size_t size, int flags)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_connectto</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gafe03cf813e644a3d2cd2de8666d7f9c8</anchor>
+ <arglist>(tnet_fd_t fd, const struct sockaddr_storage *to)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_listen</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>ga92a295abbf85a361ee5c609994e21f05</anchor>
+ <arglist>(tnet_fd_t fd, int backlog)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_fd_t</type>
+ <name>tnet_sockfd_accept</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gae4350aa61a296325ce5dfc34fae616f8</anchor>
+ <arglist>(tnet_fd_t fd, struct sockaddr *addr, socklen_t *addrlen)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_close</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gad13808723477879ca310a70c527d850a</anchor>
+ <arglist>(tnet_fd_t *fd)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_sockfd_shutdown</name>
+ <anchorfile>group__tnet__utils__group.html</anchorfile>
+ <anchor>gaba68ca319965780023e3209dae7167fa</anchor>
+ <arglist>(tnet_fd_t fd)</arglist>
+ </member>
+ </compound>
+ <compound kind="group">
+ <name>tnet_turn_group</name>
+ <title>TURN(draft-ietf-behave-turn-16) implementation.</title>
+ <filename>group__tnet__turn__group.html</filename>
+ <class kind="struct">tnet_turn_permission_s</class>
+ <class kind="struct">tnet_turn_channel_binding_s</class>
+ <class kind="struct">tnet_turn_allocation_s</class>
+ <class kind="struct">tnet_turn_attribute_channelnum_s</class>
+ <class kind="struct">tnet_turn_attribute_lifetime_s</class>
+ <class kind="struct">tnet_turn_attribute_xpeer_addr_s</class>
+ <class kind="struct">tnet_turn_attribute_data_s</class>
+ <class kind="struct">tnet_turn_attribute_xrelayed_addr_s</class>
+ <class kind="struct">tnet_turn_attribute_even_port_s</class>
+ <class kind="struct">tnet_turn_attribute_reqtrans_s</class>
+ <class kind="struct">tnet_turn_attribute_dontfrag_s</class>
+ <class kind="struct">tnet_turn_attribute_restoken_s</class>
+ <class kind="struct">tnet_turn_channel_data_s</class>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TURN_PERMISSION_TIMEOUT_DEFAULT</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gae355f01c55abfcddc5e24b59acc170f6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="define">
+ <type>#define</type>
+ <name>TNET_TURN_CHANBIND_TIMEOUT_DEFAULT</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8aa082bcb28e67d8ec00e95b2fe5406f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_permission_s</type>
+ <name>tnet_turn_permission_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga022e47cd11dd0cd6b5985948e4f47421</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_channel_binding_s</type>
+ <name>tnet_turn_channel_binding_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga869e95eb9bf494895d66ad7a68f39cd1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_allocation_s</type>
+ <name>tnet_turn_allocation_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga4962ff19fd67702f01a1b1c107b19a56</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_channelnum_s</type>
+ <name>tnet_turn_attribute_channelnum_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaa77bcb197c9e99794d67fd934d8c50c1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_lifetime_s</type>
+ <name>tnet_turn_attribute_lifetime_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga26a916f263289acaad0a56b7e374d028</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_xpeer_addr_s</type>
+ <name>tnet_turn_attribute_xpeer_addr_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaa7fa88cb2c5f7269b94a916b66083235</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_data_s</type>
+ <name>tnet_turn_attribute_data_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaaeab89d23a21fcfdaec9920fea7af597</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_xrelayed_addr_s</type>
+ <name>tnet_turn_attribute_xrelayed_addr_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga07d7abdfc37b58ca81964c22a5012e41</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_even_port_s</type>
+ <name>tnet_turn_attribute_even_port_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaa895b29c22d94e8cfcad5530a7d3264b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_reqtrans_s</type>
+ <name>tnet_turn_attribute_reqtrans_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga2ca2caa07d491a0d562e5b2e456d8f59</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_dontfrag_s</type>
+ <name>tnet_turn_attribute_dontfrag_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gab703b2d48941e0a376c5c5d82d0c2b83</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>struct tnet_turn_attribute_restoken_s</type>
+ <name>tnet_turn_attribute_restoken_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga981d08f23d6a6c2f660e0b8631703093</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="typedef">
+ <type>TNET_BEGIN_DECLS struct tnet_turn_channel_data_s</type>
+ <name>tnet_turn_channel_data_t</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga4878f9790955d14d532e4de51ac0fa5f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_channel_binding_t *</type>
+ <name>tnet_turn_channel_binding_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga103e23a60bb64dd069e6ab091784a6d4</anchor>
+ <arglist>(const tnet_turn_allocation_t *allocation)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_permission_t *</type>
+ <name>tnet_turn_permission_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8b42fc6a1e3f09cef7c7bf7c681a8218</anchor>
+ <arglist>(uint32_t timeout)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_allocation_t *</type>
+ <name>tnet_turn_allocation_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8ab0618c59d331267df779a881eb5bab</anchor>
+ <arglist>(tnet_fd_t fd, tnet_socket_type_t socket_type, const char *server_address, tnet_port_t server_port, const char *username, const char *password)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaddc8b26510c425a60140d25f131dcb85</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, tnet_stun_message_type_t type)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_allocate</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gae1e001971df0be2311a06976e2f33201</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_refresh</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga2fde61ef85bcab916a3c9ce62789bd7e</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_unallocate</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga54c0fc2d0586f3160ab4f804c8a3950e</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_channel_bind</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gacca17b6face01e3f046e75f0624545eb</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_channel_refresh</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga86f4cd5cd926f84b75a3f8c86bcc348f</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_sendindication</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga346d00b42c27cb7f9a367d790137a351</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_request_t *</type>
+ <name>tnet_turn_create_request_permission</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gad8ed3de2531edf3185d41109d9411f2b</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, va_list *app)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_send_request</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaae576cf98cdc0ef40b0b3361327ad9cf</anchor>
+ <arglist>(const tnet_nat_context_t *context, tnet_turn_allocation_t *allocation, tnet_turn_create_request_func funcptr,...)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_allocation_id_t</type>
+ <name>tnet_turn_allocate</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gad66c1ecb8963678e0d8451fef43eafd0</anchor>
+ <arglist>(const tnet_nat_context_t *nat_context, const tnet_fd_t localFD, tnet_socket_type_t socket_type)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_allocation_refresh</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8f8e9c71f4fcbddc9a95e7cf0ce333a6</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, tnet_turn_allocation_t *allocation)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_unallocate</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gadfec48a9b5519234d73373a46b24606e</anchor>
+ <arglist>(const tnet_nat_context_t *nat_context, tnet_turn_allocation_t *allocation)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_channel_binding_id_t</type>
+ <name>tnet_turn_channel_bind</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga3e6e2ae486927450c8a32d3000dd0e85</anchor>
+ <arglist>(const tnet_nat_context_t *nat_context, tnet_turn_allocation_t *allocation, struct sockaddr_storage *peer)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_channel_refresh</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga39d90117f000959af24720570c240b75</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, const tnet_turn_channel_binding_t *channel_bind)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_channel_senddata</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga8623d3c7fec8d357ad29f76633643109</anchor>
+ <arglist>(const struct tnet_nat_context_s *nat_context, const tnet_turn_channel_binding_t *channel_bind, const void *data, tsk_size_t size, int indication)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_add_permission</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gad49bc0f0bdd9832cf210825cc0b2156d</anchor>
+ <arglist>(const tnet_nat_context_t *nat_context, tnet_turn_allocation_t *allocation, const char *ipaddress, uint32_t timeout)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_channelnum_t *</type>
+ <name>tnet_turn_attribute_channelnum_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga407a64bdadf74e0cc58808f2f16de2fd</anchor>
+ <arglist>(uint16_t number)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_lifetime_t *</type>
+ <name>tnet_turn_attribute_lifetime_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga97892194ee263338e36c11d02d3c5ea2</anchor>
+ <arglist>(uint32_t lifetime)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_xpeer_addr_t *</type>
+ <name>tnet_turn_attribute_xpeer_addr_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gaf66bebd5bd8319c454a450dc092973c5</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_data_t *</type>
+ <name>tnet_turn_attribute_data_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga6e749efbc0e6c2d181b7b5572dd4a84a</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_xrelayed_addr_t *</type>
+ <name>tnet_turn_attribute_xrelayed_addr_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga27dd53bb4f5afd8fbe1b3c6450764d68</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_even_port_t *</type>
+ <name>tnet_turn_attribute_even_port_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga9201f3b08080e3d9d73d91cce22fdb6b</anchor>
+ <arglist>(unsigned R)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_reqtrans_t *</type>
+ <name>tnet_turn_attribute_reqtrans_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga0f8e1e1c00b3c62c9c451ad2dbf8419e</anchor>
+ <arglist>(tnet_proto_t protocol)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_dontfrag_t *</type>
+ <name>tnet_turn_attribute_dontfrag_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gab1baec0bd9b214f816737ccaf36846a7</anchor>
+ <arglist>()</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_turn_attribute_restoken_t *</type>
+ <name>tnet_turn_attribute_restoken_create</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga498409f84c06d567eeeeb913b01117c8</anchor>
+ <arglist>(const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>tnet_stun_attribute_t *</type>
+ <name>tnet_turn_attribute_deserialize</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>gae0fac81dd69579c064501d497cd03ea8</anchor>
+ <arglist>(tnet_stun_attribute_type_t type, uint16_t length, const void *payload, tsk_size_t payload_size)</arglist>
+ </member>
+ <member kind="function">
+ <type>int</type>
+ <name>tnet_turn_attribute_serialize</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga5c64288790f379c04d8aae14117e305c</anchor>
+ <arglist>(const tnet_stun_attribute_t *attribute, tsk_buffer_t *output)</arglist>
+ </member>
+ <member kind="function">
+ <type>tsk_buffer_t *</type>
+ <name>tnet_turn_channel_data_serialize</name>
+ <anchorfile>group__tnet__turn__group.html</anchorfile>
+ <anchor>ga00439f15cae25f78c4fd515c2ad689fc</anchor>
+ <arglist>(const tnet_turn_channel_data_t *message)</arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_address_s</name>
+ <filename>structtnet__address__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__address__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_family_t</type>
+ <name>family</name>
+ <anchorfile>structtnet__address__s.html</anchorfile>
+ <anchor>aa9ac1283cbbf630bf8c60c5ef94f3efd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>unicast</name>
+ <anchorfile>structtnet__address__s.html</anchorfile>
+ <anchor>abc788348c8761780614d2cc33a39f236</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>anycast</name>
+ <anchorfile>structtnet__address__s.html</anchorfile>
+ <anchor>a829249b4ca698adfb1ace5bf60a8256e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>multicast</name>
+ <anchorfile>structtnet__address__s.html</anchorfile>
+ <anchor>a47a0efb9804fcd897e6eb6f2ae307a44</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>dnsserver</name>
+ <anchorfile>structtnet__address__s.html</anchorfile>
+ <anchor>a9609c0c948615942826bd777e1397b7b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>ip</name>
+ <anchorfile>structtnet__address__s.html</anchorfile>
+ <anchor>afbc356cd0e25d1dbbece7c10fd025fa6</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_ctx_s</name>
+ <filename>structtnet__dhcp6__ctx__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dhcp6__ctx__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>pen</name>
+ <anchorfile>structtnet__dhcp6__ctx__s.html</anchorfile>
+ <anchor>ae2a65bb759a6405a5bf6e5de54b89d93</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>vendor_class_data</name>
+ <anchorfile>structtnet__dhcp6__ctx__s.html</anchorfile>
+ <anchor>aab350594eb87cee0541230dca6312a17</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint64_t</type>
+ <name>timeout</name>
+ <anchorfile>structtnet__dhcp6__ctx__s.html</anchorfile>
+ <anchor>a053cdea1d85795444fe1aaa6b277a0ec</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_port_t</type>
+ <name>port_client</name>
+ <anchorfile>structtnet__dhcp6__ctx__s.html</anchorfile>
+ <anchor>a834bf951592c252db10122108915b42a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_port_t</type>
+ <name>server_port</name>
+ <anchorfile>structtnet__dhcp6__ctx__s.html</anchorfile>
+ <anchor>a35123c5d12252e9bbc6950e97753deb0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_interfaces_L_t *</type>
+ <name>interfaces</name>
+ <anchorfile>structtnet__dhcp6__ctx__s.html</anchorfile>
+ <anchor>a8156a841e9546fd0b833dcdc5f23af32</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_SAFEOBJ</name>
+ <anchorfile>structtnet__dhcp6__ctx__s.html</anchorfile>
+ <anchor>a9818e976fd73889027b42c32d628169f</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_duid_en_s</name>
+ <filename>structtnet__dhcp6__duid__en__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DHCP6_DUID</name>
+ <anchorfile>structtnet__dhcp6__duid__en__s.html</anchorfile>
+ <anchor>a7d5ca788939104cbabceb0d3f5c87f12</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>en</name>
+ <anchorfile>structtnet__dhcp6__duid__en__s.html</anchorfile>
+ <anchor>a97a960f785c16a971f6c741af5c6ec2d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_buffer_t *</type>
+ <name>indentifier</name>
+ <anchorfile>structtnet__dhcp6__duid__en__s.html</anchorfile>
+ <anchor>a1c2883892c8c127410362f7d7cb9b7bb</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_duid_ll_s</name>
+ <filename>structtnet__dhcp6__duid__ll__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DHCP6_DUID</name>
+ <anchorfile>structtnet__dhcp6__duid__ll__s.html</anchorfile>
+ <anchor>a7d5ca788939104cbabceb0d3f5c87f12</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_hardware_type_t</type>
+ <name>htype</name>
+ <anchorfile>structtnet__dhcp6__duid__ll__s.html</anchorfile>
+ <anchor>af11ee3ba27d63138ab8f3d9d83ff4e31</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_buffer_t *</type>
+ <name>address</name>
+ <anchorfile>structtnet__dhcp6__duid__ll__s.html</anchorfile>
+ <anchor>a0d802bc12d5854847214fa612961d6cc</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_duid_llt_s</name>
+ <filename>structtnet__dhcp6__duid__llt__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DHCP6_DUID</name>
+ <anchorfile>structtnet__dhcp6__duid__llt__s.html</anchorfile>
+ <anchor>a7d5ca788939104cbabceb0d3f5c87f12</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_hardware_type_t</type>
+ <name>htype</name>
+ <anchorfile>structtnet__dhcp6__duid__llt__s.html</anchorfile>
+ <anchor>af11ee3ba27d63138ab8f3d9d83ff4e31</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>time</name>
+ <anchorfile>structtnet__dhcp6__duid__llt__s.html</anchorfile>
+ <anchor>ae73654f333e4363463ad8c594eca1905</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_buffer_t *</type>
+ <name>address</name>
+ <anchorfile>structtnet__dhcp6__duid__llt__s.html</anchorfile>
+ <anchor>a0d802bc12d5854847214fa612961d6cc</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_duid_s</name>
+ <filename>structtnet__dhcp6__duid__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dhcp6__duid__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>initialized</name>
+ <anchorfile>structtnet__dhcp6__duid__s.html</anchorfile>
+ <anchor>adfdbb2f146565c87384f0090dba7a73e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp6_duid_type_t</type>
+ <name>type</name>
+ <anchorfile>structtnet__dhcp6__duid__s.html</anchorfile>
+ <anchor>ae0ae09e4fc714e06fdc68d480e758dff</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_message_s</name>
+ <filename>structtnet__dhcp6__message__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dhcp6__message__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp6_message_type_t</type>
+ <name>type</name>
+ <anchorfile>structtnet__dhcp6__message__s.html</anchorfile>
+ <anchor>a21e3b33868df6c3f411acbc6b4b8a170</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>transaction_id</name>
+ <anchorfile>structtnet__dhcp6__message__s.html</anchorfile>
+ <anchor>a87f9e7ddbb607ed91afc2e1c7c9a4a52</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp6_options_L_t *</type>
+ <name>options</name>
+ <anchorfile>structtnet__dhcp6__message__s.html</anchorfile>
+ <anchor>a88b35352ad3437f608fef155b490245d</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_option_data_s</name>
+ <filename>structtnet__dhcp6__option__data__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dhcp6__option__data__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_option_identifier_s</name>
+ <filename>structtnet__dhcp6__option__identifier__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DHCP6_OPTION_DATA</name>
+ <anchorfile>structtnet__dhcp6__option__identifier__s.html</anchorfile>
+ <anchor>a28e22ea1fe86a562264c53f323dea9ef</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp6_duid_t *</type>
+ <name>duid</name>
+ <anchorfile>structtnet__dhcp6__option__identifier__s.html</anchorfile>
+ <anchor>a4b7a10003083e125dcd7c5df5d9da9b0</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_option_orequest_s</name>
+ <filename>structtnet__dhcp6__option__orequest__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DHCP6_OPTION_DATA</name>
+ <anchorfile>structtnet__dhcp6__option__orequest__s.html</anchorfile>
+ <anchor>a28e22ea1fe86a562264c53f323dea9ef</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_buffer_t *</type>
+ <name>codes</name>
+ <anchorfile>structtnet__dhcp6__option__orequest__s.html</anchorfile>
+ <anchor>ab146c1f395904867fc1f7b8e98dd04a2</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_option_s</name>
+ <filename>structtnet__dhcp6__option__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dhcp6__option__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp6_option_code_t</type>
+ <name>code</name>
+ <anchorfile>structtnet__dhcp6__option__s.html</anchorfile>
+ <anchor>a7537e49643e085c23e4f9d9f6976d5b9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>len</name>
+ <anchorfile>structtnet__dhcp6__option__s.html</anchorfile>
+ <anchor>a8aed22e2c7b283705ec82e0120515618</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp6_option_data_t *</type>
+ <name>data</name>
+ <anchorfile>structtnet__dhcp6__option__s.html</anchorfile>
+ <anchor>a600e03a1fd89a07d22a9f21611282519</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp6_option_vendorclass_s</name>
+ <filename>structtnet__dhcp6__option__vendorclass__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DHCP6_OPTION_DATA</name>
+ <anchorfile>structtnet__dhcp6__option__vendorclass__s.html</anchorfile>
+ <anchor>a28e22ea1fe86a562264c53f323dea9ef</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>enterprise_number</name>
+ <anchorfile>structtnet__dhcp6__option__vendorclass__s.html</anchorfile>
+ <anchor>a5162ea2453bd20ec2797bafba71a9fdd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_buffer_t *</type>
+ <name>vendor_class_data</name>
+ <anchorfile>structtnet__dhcp6__option__vendorclass__s.html</anchorfile>
+ <anchor>a20c300f54f6b4dd9cafecd09a4380b15</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp_ctx_s</name>
+ <filename>structtnet__dhcp__ctx__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dhcp__ctx__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>vendor_id</name>
+ <anchorfile>structtnet__dhcp__ctx__s.html</anchorfile>
+ <anchor>a73f47ae0f7d0ed50c56505b044790bb3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>hostname</name>
+ <anchorfile>structtnet__dhcp__ctx__s.html</anchorfile>
+ <anchor>af203df082d5c6dcaa0c88b07cf86466d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>max_msg_size</name>
+ <anchorfile>structtnet__dhcp__ctx__s.html</anchorfile>
+ <anchor>a8966178c69603c221293557d17f22920</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint64_t</type>
+ <name>timeout</name>
+ <anchorfile>structtnet__dhcp__ctx__s.html</anchorfile>
+ <anchor>a053cdea1d85795444fe1aaa6b277a0ec</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_port_t</type>
+ <name>port_client</name>
+ <anchorfile>structtnet__dhcp__ctx__s.html</anchorfile>
+ <anchor>a834bf951592c252db10122108915b42a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_port_t</type>
+ <name>server_port</name>
+ <anchorfile>structtnet__dhcp__ctx__s.html</anchorfile>
+ <anchor>a35123c5d12252e9bbc6950e97753deb0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_interfaces_L_t *</type>
+ <name>interfaces</name>
+ <anchorfile>structtnet__dhcp__ctx__s.html</anchorfile>
+ <anchor>a8156a841e9546fd0b833dcdc5f23af32</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_SAFEOBJ</name>
+ <anchorfile>structtnet__dhcp__ctx__s.html</anchorfile>
+ <anchor>a9818e976fd73889027b42c32d628169f</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp_message_s</name>
+ <filename>structtnet__dhcp__message__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp_message_type_t</type>
+ <name>type</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>af4ceb1a7342479133b25455d3281b2ff</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp_message_op_t</type>
+ <name>op</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>abbaa2226b43198cf6ceca447d386679d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_hardware_type_t</type>
+ <name>htype</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>af11ee3ba27d63138ab8f3d9d83ff4e31</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>hlen</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>aff25a69752648654e56c4ff3e0b1b226</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>hops</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>a2719bad26c6e7de2bc08439cea7111ce</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>xid</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>ad031a042dfee0c8192ef5e606c7a1354</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>secs</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>a3836e59e9ca2b5b77a89533388b6458f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>flags</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>a1e87af3c18a2fd36c61faf89949bdc3f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>ciaddr</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>a0952ad95e626f53511afa5180222264b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>yiaddr</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>a3cb44d0ce71c3b7201c22a41c00da379</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>siaddr</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>af938402cffa168e565c29cbc227a220a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>giaddr</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>a2719c154fb9039aa55b367468df53de0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>chaddr</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>a985fe29677d6c749d7471514cb744904</anchor>
+ <arglist>[16]</arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>sname</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>a197375c976d67dae5090e0065ead720c</anchor>
+ <arglist>[64]</arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>file</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>a5c7003134e7a7486271d4f33c2e7b7de</anchor>
+ <arglist>[128]</arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp_options_L_t *</type>
+ <name>options</name>
+ <anchorfile>structtnet__dhcp__message__s.html</anchorfile>
+ <anchor>aaef79cd8df1bc83440d0b8652d0c9c4a</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp_option_dns_s</name>
+ <filename>structtnet__dhcp__option__dns__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DHCP_OPTION</name>
+ <anchorfile>structtnet__dhcp__option__dns__s.html</anchorfile>
+ <anchor>a76ae8d097b84b331a595990bed8b5c36</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_strings_L_t *</type>
+ <name>servers</name>
+ <anchorfile>structtnet__dhcp__option__dns__s.html</anchorfile>
+ <anchor>a34baae61a8169fa438d42973816211c6</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp_option_paramslist_s</name>
+ <filename>structtnet__dhcp__option__paramslist__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DHCP_OPTION</name>
+ <anchorfile>structtnet__dhcp__option__paramslist__s.html</anchorfile>
+ <anchor>a76ae8d097b84b331a595990bed8b5c36</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp_option_s</name>
+ <filename>structtnet__dhcp__option__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dhcp__option__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>initialized</name>
+ <anchorfile>structtnet__dhcp__option__s.html</anchorfile>
+ <anchor>adfdbb2f146565c87384f0090dba7a73e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp_option_code_t</type>
+ <name>code</name>
+ <anchorfile>structtnet__dhcp__option__s.html</anchorfile>
+ <anchor>af5b9e621afaa9b16052826373021e507</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_buffer_t *</type>
+ <name>value</name>
+ <anchorfile>structtnet__dhcp__option__s.html</anchorfile>
+ <anchor>a9bcf56196da97bfeb9b5411f2a5e07f6</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp_option_sip_s</name>
+ <filename>structtnet__dhcp__option__sip__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DHCP_OPTION</name>
+ <anchorfile>structtnet__dhcp__option__sip__s.html</anchorfile>
+ <anchor>a76ae8d097b84b331a595990bed8b5c36</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_strings_L_t *</type>
+ <name>servers</name>
+ <anchorfile>structtnet__dhcp__option__sip__s.html</anchorfile>
+ <anchor>a34baae61a8169fa438d42973816211c6</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dhcp_params_s</name>
+ <filename>structtnet__dhcp__params__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dhcp__params__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dhcp_option_code_t</type>
+ <name>codes</name>
+ <anchorfile>structtnet__dhcp__params__s.html</anchorfile>
+ <anchor>a1be3fd6101ab9b0e039d4cf30e79cc46</anchor>
+ <arglist>[TNET_DHCP_MAX_CODES]</arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>codes_count</name>
+ <anchorfile>structtnet__dhcp__params__s.html</anchorfile>
+ <anchor>a36227aefbb616902b06fbf9fb123123e</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_a_s</name>
+ <filename>structtnet__dns__a__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__a__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>address</name>
+ <anchorfile>structtnet__dns__a__s.html</anchorfile>
+ <anchor>a879a8cdf605d02f8af8b2e216b8764f2</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_aaaa_s</name>
+ <filename>structtnet__dns__aaaa__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__aaaa__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>address</name>
+ <anchorfile>structtnet__dns__aaaa__s.html</anchorfile>
+ <anchor>a879a8cdf605d02f8af8b2e216b8764f2</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_cache_entry_s</name>
+ <filename>structtnet__dns__cache__entry__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dns__cache__entry__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>qname</name>
+ <anchorfile>structtnet__dns__cache__entry__s.html</anchorfile>
+ <anchor>a5a317b1553299b3cbe3ef6d6d2edcffc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dns_qclass_t</type>
+ <name>qclass</name>
+ <anchorfile>structtnet__dns__cache__entry__s.html</anchorfile>
+ <anchor>a15b4f97c9e5e000874a08a001eeb7733</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dns_qtype_t</type>
+ <name>qtype</name>
+ <anchorfile>structtnet__dns__cache__entry__s.html</anchorfile>
+ <anchor>a3a9ecb9a634fe9bb31a40188e63a0370</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint64_t</type>
+ <name>epoch</name>
+ <anchorfile>structtnet__dns__cache__entry__s.html</anchorfile>
+ <anchor>a7d1c4feed1318aeb0b96f657d87cd1ab</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dns_response_t *</type>
+ <name>response</name>
+ <anchorfile>structtnet__dns__cache__entry__s.html</anchorfile>
+ <anchor>ac9ec66f6ecc7aa0aeddcd20828199d68</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_cname_s</name>
+ <filename>structtnet__dns__cname__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__cname__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>cname</name>
+ <anchorfile>structtnet__dns__cname__s.html</anchorfile>
+ <anchor>a6b787eeec4924a37fc531cd8b950d9f9</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_ctx_s</name>
+ <filename>structtnet__dns__ctx__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dns__ctx__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint64_t</type>
+ <name>timeout</name>
+ <anchorfile>structtnet__dns__ctx__s.html</anchorfile>
+ <anchor>a053cdea1d85795444fe1aaa6b277a0ec</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>recursion</name>
+ <anchorfile>structtnet__dns__ctx__s.html</anchorfile>
+ <anchor>a97e982c6f7d2346cb1d95160a6667c3a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>edns0</name>
+ <anchorfile>structtnet__dns__ctx__s.html</anchorfile>
+ <anchor>ae4004c3075864042e3cc5cfc0ca333b3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>caching</name>
+ <anchorfile>structtnet__dns__ctx__s.html</anchorfile>
+ <anchor>a3c98bef376fb846129f5ea3f78eddb98</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>int32_t</type>
+ <name>cache_ttl</name>
+ <anchorfile>structtnet__dns__ctx__s.html</anchorfile>
+ <anchor>a4000992e7b3bb97836c9ab0c296c5c64</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_port_t</type>
+ <name>server_port</name>
+ <anchorfile>structtnet__dns__ctx__s.html</anchorfile>
+ <anchor>a35123c5d12252e9bbc6950e97753deb0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dns_cache_t *</type>
+ <name>cache</name>
+ <anchorfile>structtnet__dns__ctx__s.html</anchorfile>
+ <anchor>adac05d42fe5d85b2b1b7eaddd61d89d3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_addresses_L_t *</type>
+ <name>servers</name>
+ <anchorfile>structtnet__dns__ctx__s.html</anchorfile>
+ <anchor>af91849b97bc1300e93e88f65a4ee44b1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_SAFEOBJ</name>
+ <anchorfile>structtnet__dns__ctx__s.html</anchorfile>
+ <anchor>a9818e976fd73889027b42c32d628169f</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_message_s</name>
+ <filename>structtnet__dns__message__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dns__message__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_dns_message_s::@0</type>
+ <name>Header</name>
+ <anchorfile>structtnet__dns__message__s.html</anchorfile>
+ <anchor>a3fb15af2e8eecc6a97afbe7f5e27980f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_dns_message_s::@1</type>
+ <name>Question</name>
+ <anchorfile>structtnet__dns__message__s.html</anchorfile>
+ <anchor>ab11a7098fcf552ad821a90a5ba6f4fca</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dns_rrs_L_t *</type>
+ <name>Answers</name>
+ <anchorfile>structtnet__dns__message__s.html</anchorfile>
+ <anchor>a67f770a7758696b3e5a5809eff26fb91</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dns_rrs_L_t *</type>
+ <name>Authorities</name>
+ <anchorfile>structtnet__dns__message__s.html</anchorfile>
+ <anchor>a07b3c715e236c3e00b3db70b46857c8a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dns_rrs_L_t *</type>
+ <name>Additionals</name>
+ <anchorfile>structtnet__dns__message__s.html</anchorfile>
+ <anchor>a04fa4444757b7ded3f659e622b5a2924</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_mx_s</name>
+ <filename>structtnet__dns__mx__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__mx__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>preference</name>
+ <anchorfile>structtnet__dns__mx__s.html</anchorfile>
+ <anchor>a0895a8ef7de652dbf7ac2ece95f267df</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>exchange</name>
+ <anchorfile>structtnet__dns__mx__s.html</anchorfile>
+ <anchor>ae456886310fcf4a36c0d7a789ad3cb69</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_naptr_s</name>
+ <filename>structtnet__dns__naptr__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__naptr__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>order</name>
+ <anchorfile>structtnet__dns__naptr__s.html</anchorfile>
+ <anchor>afd05883aec8e6070b12674a77c541025</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>preference</name>
+ <anchorfile>structtnet__dns__naptr__s.html</anchorfile>
+ <anchor>a0895a8ef7de652dbf7ac2ece95f267df</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>flags</name>
+ <anchorfile>structtnet__dns__naptr__s.html</anchorfile>
+ <anchor>a4db5c33b255239e4bc2f302bc34a5339</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>services</name>
+ <anchorfile>structtnet__dns__naptr__s.html</anchorfile>
+ <anchor>aa5bac2721b92fccd4e1ad17978c69ec4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>regexp</name>
+ <anchorfile>structtnet__dns__naptr__s.html</anchorfile>
+ <anchor>ac1d9b998a1dabf12492d943e3bb765bb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>replacement</name>
+ <anchorfile>structtnet__dns__naptr__s.html</anchorfile>
+ <anchor>ac92b8d0fe1aa141a4ae8c7d0c0dae69b</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_ns_s</name>
+ <filename>structtnet__dns__ns__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__ns__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>nsdname</name>
+ <anchorfile>structtnet__dns__ns__s.html</anchorfile>
+ <anchor>a1d173c3317758caf3501a48cb6c0cf48</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_opt_s</name>
+ <filename>structtnet__dns__opt__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__opt__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_ptr_s</name>
+ <filename>structtnet__dns__ptr__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__ptr__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>ptrdname</name>
+ <anchorfile>structtnet__dns__ptr__s.html</anchorfile>
+ <anchor>a243ff266ee3a887c216f55296768f10d</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_rr_s</name>
+ <filename>structtnet__dns__rr__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dns__rr__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>initialized</name>
+ <anchorfile>structtnet__dns__rr__s.html</anchorfile>
+ <anchor>adfdbb2f146565c87384f0090dba7a73e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>name</name>
+ <anchorfile>structtnet__dns__rr__s.html</anchorfile>
+ <anchor>a5ac083a645d964373f022d03df4849c8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dns_qtype_t</type>
+ <name>qtype</name>
+ <anchorfile>structtnet__dns__rr__s.html</anchorfile>
+ <anchor>a3a9ecb9a634fe9bb31a40188e63a0370</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dns_qclass_t</type>
+ <name>qclass</name>
+ <anchorfile>structtnet__dns__rr__s.html</anchorfile>
+ <anchor>a15b4f97c9e5e000874a08a001eeb7733</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>int32_t</type>
+ <name>ttl</name>
+ <anchorfile>structtnet__dns__rr__s.html</anchorfile>
+ <anchor>adcbcef3ebe212c2b2b6c75f10d9186c8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>rdlength</name>
+ <anchorfile>structtnet__dns__rr__s.html</anchorfile>
+ <anchor>af06969277715677d7441c9b816daa2ec</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>void *</type>
+ <name>rpdata</name>
+ <anchorfile>structtnet__dns__rr__s.html</anchorfile>
+ <anchor>a5c9a31069ba9dc307f5c3c383058873b</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_soa_s</name>
+ <filename>structtnet__dns__soa__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__soa__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>mname</name>
+ <anchorfile>structtnet__dns__soa__s.html</anchorfile>
+ <anchor>a8721eff2350ed6076b3b331690c9eb67</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>rname</name>
+ <anchorfile>structtnet__dns__soa__s.html</anchorfile>
+ <anchor>a4abc08d8bf8e71d81f1928b77675d9a8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>serial</name>
+ <anchorfile>structtnet__dns__soa__s.html</anchorfile>
+ <anchor>a1149ca4bd0659030412db8e77bebdf88</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>refresh</name>
+ <anchorfile>structtnet__dns__soa__s.html</anchorfile>
+ <anchor>a3185284e70c8e62827fa3c7932b82ce8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>retry</name>
+ <anchorfile>structtnet__dns__soa__s.html</anchorfile>
+ <anchor>ae544e10bfc5a36197ae704603a9a6205</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>expire</name>
+ <anchorfile>structtnet__dns__soa__s.html</anchorfile>
+ <anchor>ad2736d3cd8e2ca2d37da2b69cb721134</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>minimum</name>
+ <anchorfile>structtnet__dns__soa__s.html</anchorfile>
+ <anchor>a783317953fb3acf817a73a8af09d3636</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_srv_s</name>
+ <filename>structtnet__dns__srv__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__srv__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>priority</name>
+ <anchorfile>structtnet__dns__srv__s.html</anchorfile>
+ <anchor>a0815784d41b3c13d42ce22367abfba1d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>weight</name>
+ <anchorfile>structtnet__dns__srv__s.html</anchorfile>
+ <anchor>a3c304b42c785c4cc5fa46842e2845a6b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>port</name>
+ <anchorfile>structtnet__dns__srv__s.html</anchorfile>
+ <anchor>a8e0798404bf2cf5dabb84c5ba9a4f236</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>target</name>
+ <anchorfile>structtnet__dns__srv__s.html</anchorfile>
+ <anchor>a23b26cdb3a71f525caf03b57f68d47fa</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dns_txt_s</name>
+ <filename>structtnet__dns__txt__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_DECLARE_DNS_RR</name>
+ <anchorfile>structtnet__dns__txt__s.html</anchorfile>
+ <anchor>a5c892c7c008cc59b0067d98a30c533cd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>txt_data</name>
+ <anchorfile>structtnet__dns__txt__s.html</anchorfile>
+ <anchor>aaa858f1e56c43a4400f94586c9ca8712</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_dtls_socket_s</name>
+ <filename>structtnet__dtls__socket__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__dtls__socket__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_fd_t</type>
+ <name>fd</name>
+ <anchorfile>structtnet__dtls__socket__s.html</anchorfile>
+ <anchor>a89776c821e7cb62a4acac46798a84137</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>verify_peer</name>
+ <anchorfile>structtnet__dtls__socket__s.html</anchorfile>
+ <anchor>ac3bbf4e3b1bc3ea9c47f0fc43969dac2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>use_srtp</name>
+ <anchorfile>structtnet__dtls__socket__s.html</anchorfile>
+ <anchor>a07a7a29b74a7cecdc4392e6aa547005f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>handshake_completed</name>
+ <anchorfile>structtnet__dtls__socket__s.html</anchorfile>
+ <anchor>a9d9b346395e6d39d82414e5dbbc99dac</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dtls_setup_t</type>
+ <name>setup</name>
+ <anchorfile>structtnet__dtls__socket__s.html</anchorfile>
+ <anchor>a45067f39a61d7d389a19739fd1e59b99</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_dtls_socket_s::@4</type>
+ <name>cb</name>
+ <anchorfile>structtnet__dtls__socket__s.html</anchorfile>
+ <anchor>adba381cb3517a407757cb0bacf239fbb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_dtls_socket_s::@5</type>
+ <name>remote</name>
+ <anchorfile>structtnet__dtls__socket__s.html</anchorfile>
+ <anchor>a2d62e3cc37a43c42b2e350fc1d70381b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_dtls_socket_s::@6</type>
+ <name>local</name>
+ <anchorfile>structtnet__dtls__socket__s.html</anchorfile>
+ <anchor>a654feace44e7c42b656ff47695fa3209</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_SAFEOBJ</name>
+ <anchorfile>structtnet__dtls__socket__s.html</anchorfile>
+ <anchor>a9818e976fd73889027b42c32d628169f</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_ice_action_s</name>
+ <filename>structtnet__ice__action__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__ice__action__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_fsm_action_id</type>
+ <name>id</name>
+ <anchorfile>structtnet__ice__action__s.html</anchorfile>
+ <anchor>afa188fbd86824e693af7d82baf1831a7</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_ice_candidate_s</name>
+ <filename>structtnet__ice__candidate__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ice_cand_type_t</type>
+ <name>type_e</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>ab7208769aa8829731c5cfdc820849f1f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>foundation</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a7dc7989fc6a4901626924310cebadbac</anchor>
+ <arglist>[33]</arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>comp_id</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a30d7364b567d7c341a5dc3f602136363</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>transport_str</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a16edd675ed7c739a518c7df27ca57d82</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>enum tnet_socket_type_e</type>
+ <name>transport_e</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>ae4e142d80ab962928fc48710ebc9256e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>priority</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a90249de64da5ae5d7acd34da7ea1b857</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>cand_type_str</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>abee5149305f31cc6ed5e356a5b9547f8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ip_t</type>
+ <name>connection_addr</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>ae862117942242057beb16b59e568fcd6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_port_t</type>
+ <name>port</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a804003d8ce1732a48fc0a8d3f44fcc1c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_params_L_t *</type>
+ <name>extension_att_list</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a851450e616fa22e16448808be6e030a7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>is_ice_jingle</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a2f30e8927ccd387faaf5628d115ae17c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>is_rtp</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a910d991f863a83bc7f53ef12bc174ce5</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>is_video</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>aa32a2ad18730f160578396d76bc9cbb0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>local_pref</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>ab9c182df2591c34c8185b98cb0360252</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>ufrag</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a3b4a16bb0327f02abc59505b25e77bb8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>pwd</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a4be832ac49cb1384b79b9423028f1d54</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_socket_s *</type>
+ <name>socket</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>aa6ef92be590a80571ef2297ef5a3479d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_ice_candidate_s::@2</type>
+ <name>stun</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>a52c3b5eb6826c5338d8b5e3c177a30fa</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>tostring</name>
+ <anchorfile>structtnet__ice__candidate__s.html</anchorfile>
+ <anchor>ac53a959d1e2819b4dae0c9b5d4f8f5d8</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_ice_ctx_s</name>
+ <filename>structtnet__ice__ctx__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_RUNNABLE</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>ae8fba71ac54cd6376ba9e5ed1cc87cf3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>is_started</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>aceed659b1d0a7bdb1ddcc2480b6273f9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>is_active</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>ac8e3cacbc0f857762970f6b9be72a4e2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ice_callback_f</type>
+ <name>callback</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a5fc2712f91a0b561cbd5232e8506c3cc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const void *</type>
+ <name>userdata</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a2aa76a7bfd06a16154eccdd30d6f6393</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>use_ipv6</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a558e28da1766e51b8cba545747aa9eed</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>use_rtcp</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>ae3425b99ca7b44979bb44d6f46356238</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>use_rtcpmux</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a3ff7682ebd9100401e4344ddc38779e7</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>is_video</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>aa32a2ad18730f160578396d76bc9cbb0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>unicast</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>ab849120f12135af90808a5a3cee69aac</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>anycast</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>aee319295484f210ff8d76bd12c1c749d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>multicast</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a0721609fcddaa98a4c47a48b64faaabe</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>is_controlling</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a505b4f2717219bc9a55dd48dc8753d8a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>is_ice_jingle</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a2f30e8927ccd387faaf5628d115ae17c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint64_t</type>
+ <name>tie_breaker</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a5581ce626352db2070cae43032c963a6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint64_t</type>
+ <name>concheck_timeout</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a35765e5bbc5be1762e99e6fd0b436793</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const void *</type>
+ <name>rtp_callback_data</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a6d77826979298b328326b282bd787899</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ice_rtp_callback_f</type>
+ <name>rtp_callback</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a43dfd07c697f57c396f8f04d542deeb6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>ufrag</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a3b4a16bb0327f02abc59505b25e77bb8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>pwd</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a4be832ac49cb1384b79b9423028f1d54</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_timer_manager_handle_t *</type>
+ <name>h_timer_mgr</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a5fd624501a8012544ccaf1bfbe9cfe6d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_fsm_t *</type>
+ <name>fsm</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a0cc2337becbdef2e7ea539f61019fdbd</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ice_candidates_L_t *</type>
+ <name>candidates_local</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a6a3700734a198d6c04c5a7f428f66c35</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ice_candidates_L_t *</type>
+ <name>candidates_remote</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a87907f26f08ddd55e8d2bd65f7454ad4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ice_pairs_L_t *</type>
+ <name>candidates_pairs</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a3f0d3e9fc285be5693fe2e5f14ae682c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>have_nominated_offer</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>ab820474c96a4e2752af92ae3c5352052</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>have_nominated_answer</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a78cff6175205e1c23e536a9d09220624</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>have_nominated_symetric</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a7bc095414b42e4af61747c3f4c037789</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>RTO</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>aebe0faf98d3286e1406eb88b460f0808</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>Rc</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a4df78cbd063bbc725d99e2f80b391cb1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_ice_ctx_s::@3</type>
+ <name>stun</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a9c0864c5426d106b90ee56f76cd5e92e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_SAFEOBJ</name>
+ <anchorfile>structtnet__ice__ctx__s.html</anchorfile>
+ <anchor>a9818e976fd73889027b42c32d628169f</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_ice_event_s</name>
+ <filename>structtnet__ice__event__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__ice__event__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ice_event_type_t</type>
+ <name>type</name>
+ <anchorfile>structtnet__ice__event__s.html</anchorfile>
+ <anchor>ad65eebeead91a113dfd8c7a5c8f82b0f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>phrase</name>
+ <anchorfile>structtnet__ice__event__s.html</anchorfile>
+ <anchor>a601977f3c7b2d461e3723ca8ef7926f0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_ice_action_s *</type>
+ <name>action</name>
+ <anchorfile>structtnet__ice__event__s.html</anchorfile>
+ <anchor>a0ecb51cb1b029389ef4257b23dd9b075</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_ice_ctx_s *</type>
+ <name>ctx</name>
+ <anchorfile>structtnet__ice__event__s.html</anchorfile>
+ <anchor>a5c998d86fc92f46033f738f1f761ef4f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const void *</type>
+ <name>userdata</name>
+ <anchorfile>structtnet__ice__event__s.html</anchorfile>
+ <anchor>a2aa76a7bfd06a16154eccdd30d6f6393</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_ice_pair_s</name>
+ <filename>structtnet__ice__pair__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__ice__pair__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint64_t</type>
+ <name>priority</name>
+ <anchorfile>structtnet__ice__pair__s.html</anchorfile>
+ <anchor>af43b7b00bdbaf3d0602086885a410899</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ice_pair_state_t</type>
+ <name>state_offer</name>
+ <anchorfile>structtnet__ice__pair__s.html</anchorfile>
+ <anchor>af268a8c411b9f018e0254ed4da093825</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ice_pair_state_t</type>
+ <name>state_answer</name>
+ <anchorfile>structtnet__ice__pair__s.html</anchorfile>
+ <anchor>a220b0b99453f807075ad530c39756343</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>is_ice_jingle</name>
+ <anchorfile>structtnet__ice__pair__s.html</anchorfile>
+ <anchor>a2f30e8927ccd387faaf5628d115ae17c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>is_controlling</name>
+ <anchorfile>structtnet__ice__pair__s.html</anchorfile>
+ <anchor>a505b4f2717219bc9a55dd48dc8753d8a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint64_t</type>
+ <name>tie_breaker</name>
+ <anchorfile>structtnet__ice__pair__s.html</anchorfile>
+ <anchor>a5581ce626352db2070cae43032c963a6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_ice_candidate_s *</type>
+ <name>candidate_offer</name>
+ <anchorfile>structtnet__ice__pair__s.html</anchorfile>
+ <anchor>a438bfe5089fc56f5297a5f40adc199be</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_ice_candidate_s *</type>
+ <name>candidate_answer</name>
+ <anchorfile>structtnet__ice__pair__s.html</anchorfile>
+ <anchor>adbb3f8f093eed2e9995a74dbe3ada407</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_stun_message_s *</type>
+ <name>last_request</name>
+ <anchorfile>structtnet__ice__pair__s.html</anchorfile>
+ <anchor>a9b53797dee1dd1569721b615a573aaab</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_interface_s</name>
+ <filename>structtnet__interface__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__interface__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>index</name>
+ <anchorfile>structtnet__interface__s.html</anchorfile>
+ <anchor>a360ebf6209d16512186ca7adb893abbb</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>description</name>
+ <anchorfile>structtnet__interface__s.html</anchorfile>
+ <anchor>a8444d6e0dfe2bbab0b5e7b24308f1559</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t *</type>
+ <name>mac_address</name>
+ <anchorfile>structtnet__interface__s.html</anchorfile>
+ <anchor>a2571db5ff6bc43c1d6c4f3b9c8aefd87</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_size_t</type>
+ <name>mac_address_length</name>
+ <anchorfile>structtnet__interface__s.html</anchorfile>
+ <anchor>a9d62b42964509e35907e16d57ab116a5</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_nat_context_s</name>
+ <filename>structtnet__nat__context__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_socket_type_t</type>
+ <name>socket_type</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>a27db52c3553ad7f3a50a3f846128f5f3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>username</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>a9b20c006bd90a09e1465fb668700e81d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>password</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>a59460a3ff2c12443d1022e5cc0fba85c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>software</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>ab7dea44af93feeae91fbc350466cd75b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>server_address</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>afbcb0d71ddd626fabdbf6646e7db8b99</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_port_t</type>
+ <name>server_port</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>a35123c5d12252e9bbc6950e97753deb0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>RTO</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>aebe0faf98d3286e1406eb88b460f0808</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>Rc</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>a4df78cbd063bbc725d99e2f80b391cb1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>enable_dontfrag</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>ad92b1c73d8fc7717638c6a6785b0e1b9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>enable_integrity</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>a55e74a4b337b7b26c1b9edee06fec693</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>enable_evenport</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>a43b8469c663698dd9c1c409de1c2452b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>enable_fingerprint</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>aaf103f3994e9b9c4b13612755ccb61d0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>use_dnsquery</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>a37ce943df13721eabe344a56caab6135</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_turn_allocations_L_t *</type>
+ <name>allocations</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>ab1bc1c207c419d587ddc9272a48c84ba</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_bindings_L_t *</type>
+ <name>stun_bindings</name>
+ <anchorfile>structtnet__nat__context__s.html</anchorfile>
+ <anchor>ac49251b98f3dc1c92f5d2293e9badb8c</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_socket_s</name>
+ <filename>structtnet__socket__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__socket__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_socket_type_t</type>
+ <name>type</name>
+ <anchorfile>structtnet__socket__s.html</anchorfile>
+ <anchor>ae2a94a75704f25f33d3f032e34feb205</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_fd_t</type>
+ <name>fd</name>
+ <anchorfile>structtnet__socket__s.html</anchorfile>
+ <anchor>a89776c821e7cb62a4acac46798a84137</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_ip_t</type>
+ <name>ip</name>
+ <anchorfile>structtnet__socket__s.html</anchorfile>
+ <anchor>a520b46ef780bbe6f719ca59c3bfecd74</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>port</name>
+ <anchorfile>structtnet__socket__s.html</anchorfile>
+ <anchor>a8e0798404bf2cf5dabb84c5ba9a4f236</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_tls_socket_handle_t *</type>
+ <name>tlshandle</name>
+ <anchorfile>structtnet__socket__s.html</anchorfile>
+ <anchor>afb9a3122a38768304a5134beb27e1298</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_dtls_socket_handle_t *</type>
+ <name>dtlshandle</name>
+ <anchorfile>structtnet__socket__s.html</anchorfile>
+ <anchor>aa0089985f6797dd810fd77090fbdd2b2</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_altserver_s</name>
+ <filename>structtnet__stun__attribute__altserver__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__altserver__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_addr_family_t</type>
+ <name>family</name>
+ <anchorfile>structtnet__stun__attribute__altserver__s.html</anchorfile>
+ <anchor>a49f24db0b2265a9d515199d570dd4e38</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>port</name>
+ <anchorfile>structtnet__stun__attribute__altserver__s.html</anchorfile>
+ <anchor>a8e0798404bf2cf5dabb84c5ba9a4f236</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>server</name>
+ <anchorfile>structtnet__stun__attribute__altserver__s.html</anchorfile>
+ <anchor>af4d154cbfef4303a47869a02cd589624</anchor>
+ <arglist>[128]</arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_errorcode_s</name>
+ <filename>structtnet__stun__attribute__errorcode__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__errorcode__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>_class</name>
+ <anchorfile>structtnet__stun__attribute__errorcode__s.html</anchorfile>
+ <anchor>a1e336cb34c9f32b8d3b30ef50e4d5212</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>number</name>
+ <anchorfile>structtnet__stun__attribute__errorcode__s.html</anchorfile>
+ <anchor>af57eaec6f3dec6de717735725c9908a6</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>reason_phrase</name>
+ <anchorfile>structtnet__stun__attribute__errorcode__s.html</anchorfile>
+ <anchor>a18bf51f0b416cc27103a7a47db3442de</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_fingerprint_s</name>
+ <filename>structtnet__stun__attribute__fingerprint__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__fingerprint__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>value</name>
+ <anchorfile>structtnet__stun__attribute__fingerprint__s.html</anchorfile>
+ <anchor>ae7f66047e6e39ba2bb6af8b95f00d1dd</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_ice_controlled_s</name>
+ <filename>structtnet__stun__attribute__ice__controlled__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__ice__controlled__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint64_t</type>
+ <name>value</name>
+ <anchorfile>structtnet__stun__attribute__ice__controlled__s.html</anchorfile>
+ <anchor>a4e630859cc0e2a22bd6acf39a6a8e218</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_ice_controlling_s</name>
+ <filename>structtnet__stun__attribute__ice__controlling__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__ice__controlling__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint64_t</type>
+ <name>value</name>
+ <anchorfile>structtnet__stun__attribute__ice__controlling__s.html</anchorfile>
+ <anchor>a4e630859cc0e2a22bd6acf39a6a8e218</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_ice_priority_s</name>
+ <filename>structtnet__stun__attribute__ice__priority__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__ice__priority__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>value</name>
+ <anchorfile>structtnet__stun__attribute__ice__priority__s.html</anchorfile>
+ <anchor>ae7f66047e6e39ba2bb6af8b95f00d1dd</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_ice_use_candidate_s</name>
+ <filename>structtnet__stun__attribute__ice__use__candidate__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__ice__use__candidate__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_integrity_s</name>
+ <filename>structtnet__stun__attribute__integrity__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__integrity__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_sha1digest_t</type>
+ <name>sha1digest</name>
+ <anchorfile>structtnet__stun__attribute__integrity__s.html</anchorfile>
+ <anchor>a7c7001f4d433128aec28db91a69bc8ed</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_mapped_addr_s</name>
+ <filename>structtnet__stun__attribute__mapped__addr__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__mapped__addr__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_addr_family_t</type>
+ <name>family</name>
+ <anchorfile>structtnet__stun__attribute__mapped__addr__s.html</anchorfile>
+ <anchor>a49f24db0b2265a9d515199d570dd4e38</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>port</name>
+ <anchorfile>structtnet__stun__attribute__mapped__addr__s.html</anchorfile>
+ <anchor>a8e0798404bf2cf5dabb84c5ba9a4f236</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>address</name>
+ <anchorfile>structtnet__stun__attribute__mapped__addr__s.html</anchorfile>
+ <anchor>ae4879450c8041e3ab7fd9d958557f826</anchor>
+ <arglist>[16]</arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_nonce_s</name>
+ <filename>structtnet__stun__attribute__nonce__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__nonce__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>value</name>
+ <anchorfile>structtnet__stun__attribute__nonce__s.html</anchorfile>
+ <anchor>a4e9aec275e566b978a3ccb4e043d8c61</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_realm_s</name>
+ <filename>structtnet__stun__attribute__realm__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__realm__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>value</name>
+ <anchorfile>structtnet__stun__attribute__realm__s.html</anchorfile>
+ <anchor>a4e9aec275e566b978a3ccb4e043d8c61</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_s</name>
+ <filename>structtnet__stun__attribute__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__stun__attribute__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_attribute_type_t</type>
+ <name>type</name>
+ <anchorfile>structtnet__stun__attribute__s.html</anchorfile>
+ <anchor>a612b04c5b268170d0fb2ac0ef564ed83</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>length</name>
+ <anchorfile>structtnet__stun__attribute__s.html</anchorfile>
+ <anchor>a1892eba2086d12ac2b09005aeb09ea3b</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_software_s</name>
+ <filename>structtnet__stun__attribute__software__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__software__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>value</name>
+ <anchorfile>structtnet__stun__attribute__software__s.html</anchorfile>
+ <anchor>a4e9aec275e566b978a3ccb4e043d8c61</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_unknowns_s</name>
+ <filename>structtnet__stun__attribute__unknowns__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__unknowns__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_buffer_t *</type>
+ <name>value</name>
+ <anchorfile>structtnet__stun__attribute__unknowns__s.html</anchorfile>
+ <anchor>a9bcf56196da97bfeb9b5411f2a5e07f6</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_username_s</name>
+ <filename>structtnet__stun__attribute__username__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__username__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>value</name>
+ <anchorfile>structtnet__stun__attribute__username__s.html</anchorfile>
+ <anchor>a4e9aec275e566b978a3ccb4e043d8c61</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_attribute_xmapped_addr_s</name>
+ <filename>structtnet__stun__attribute__xmapped__addr__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__stun__attribute__xmapped__addr__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_addr_family_t</type>
+ <name>family</name>
+ <anchorfile>structtnet__stun__attribute__xmapped__addr__s.html</anchorfile>
+ <anchor>a49f24db0b2265a9d515199d570dd4e38</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>xport</name>
+ <anchorfile>structtnet__stun__attribute__xmapped__addr__s.html</anchorfile>
+ <anchor>ac021791c2ad249b108a5155d4c252a9f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>xaddress</name>
+ <anchorfile>structtnet__stun__attribute__xmapped__addr__s.html</anchorfile>
+ <anchor>ac365f9f3b4cedc84224afd91b2597ccb</anchor>
+ <arglist>[16]</arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_binding_s</name>
+ <filename>structtnet__stun__binding__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_binding_id_t</type>
+ <name>id</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>a68541ba67a916edaa34f4da31009b97f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>username</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>a9b20c006bd90a09e1465fb668700e81d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>password</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>a59460a3ff2c12443d1022e5cc0fba85c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>realm</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>a78e609bc32bd5a9820209fe62b39963f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>nonce</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>a814af5af8d9ea73885c8216c0e547e2a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>software</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>ab7dea44af93feeae91fbc350466cd75b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_fd_t</type>
+ <name>localFD</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>a2f7fda9a08aade674a360b301268cd92</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_socket_type_t</type>
+ <name>socket_type</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>a27db52c3553ad7f3a50a3f846128f5f3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct sockaddr_storage</type>
+ <name>server</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>acbcb80535e518b7b9f636338f948b88c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_attribute_mapped_addr_t *</type>
+ <name>maddr</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>a1bb895a0f6e6fbe93ac0bc346bc52526</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_attribute_xmapped_addr_t *</type>
+ <name>xmaddr</name>
+ <anchorfile>structtnet__stun__binding__s.html</anchorfile>
+ <anchor>a5405872105ef7f32cabddc425993f69a</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_stun_message_s</name>
+ <filename>structtnet__stun__message__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_message_type_t</type>
+ <name>type</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>adc708b7d327e9a9f6e5d1a9f16fe1749</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>length</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>a1892eba2086d12ac2b09005aeb09ea3b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>cookie</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>af9c930e4206148386b1d991e325a132d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_transacid_t</type>
+ <name>transaction_id</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>ab4cd124218c6c7c7ddf534b043600832</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>fingerprint</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>a493cb3f41b0f9ef0178425b3fbde3ab1</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>integrity</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>a84c2663b2f0442ae8a425bc5f30bda7e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>dontfrag</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>ab49b896e3ea7fc8cf5f432b267defcb0</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>nointegrity</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>a5c9b21c563ac7ab9fda61a7e93a34250</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>username</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>a9b20c006bd90a09e1465fb668700e81d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>password</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>a59460a3ff2c12443d1022e5cc0fba85c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>realm</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>a78e609bc32bd5a9820209fe62b39963f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>nonce</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>a814af5af8d9ea73885c8216c0e547e2a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_attributes_L_t *</type>
+ <name>attributes</name>
+ <anchorfile>structtnet__stun__message__s.html</anchorfile>
+ <anchor>ae438e8c15b79d8a020645d347bfa1b07</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_tls_socket_s</name>
+ <filename>structtnet__tls__socket__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__tls__socket__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_fd_t</type>
+ <name>fd</name>
+ <anchorfile>structtnet__tls__socket__s.html</anchorfile>
+ <anchor>a89776c821e7cb62a4acac46798a84137</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_SAFEOBJ</name>
+ <anchorfile>structtnet__tls__socket__s.html</anchorfile>
+ <anchor>a9818e976fd73889027b42c32d628169f</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_transport_event_s</name>
+ <filename>structtnet__transport__event__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__transport__event__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_transport_event_type_t</type>
+ <name>type</name>
+ <anchorfile>structtnet__transport__event__s.html</anchorfile>
+ <anchor>a312995fc2313cbfd77bf91982e33fb20</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>void *</type>
+ <name>data</name>
+ <anchorfile>structtnet__transport__event__s.html</anchorfile>
+ <anchor>a735984d41155bc1032e09bece8f8d66d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_size_t</type>
+ <name>size</name>
+ <anchorfile>structtnet__transport__event__s.html</anchorfile>
+ <anchor>a2af13611e30c0884ab2e1837c4da8282</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const void *</type>
+ <name>callback_data</name>
+ <anchorfile>structtnet__transport__event__s.html</anchorfile>
+ <anchor>a7322346207ed833d5550334332388ff9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_fd_t</type>
+ <name>local_fd</name>
+ <anchorfile>structtnet__transport__event__s.html</anchorfile>
+ <anchor>afa7f2e7bc012cbcc028e247c726043fc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct sockaddr_storage</type>
+ <name>remote_addr</name>
+ <anchorfile>structtnet__transport__event__s.html</anchorfile>
+ <anchor>ae0831b58d62cf11710b2638982259cfb</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_transport_s</name>
+ <filename>structtnet__transport__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_RUNNABLE</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>ae8fba71ac54cd6376ba9e5ed1cc87cf3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_socket_type_t</type>
+ <name>type</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>ae2a94a75704f25f33d3f032e34feb205</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>local_ip</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>a39812ff38e55c55387e819985e9f0d20</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>local_host</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>a5581c3fd932c186d16c55dd83499788b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_port_t</type>
+ <name>req_local_port</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>af89530ad71276773e469c5e90ae18d6c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_port_t</type>
+ <name>bind_local_port</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>ae57f3ae4b492ff17c9aed39764016540</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_nat_context_handle_t *</type>
+ <name>natt_ctx</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>a4e40b6b4f2c827184bbfca2abafb683b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_socket_t *</type>
+ <name>master</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>a451156669819ac6a2cad58a45835c391</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_object_t *</type>
+ <name>context</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>a59bd43e8ef51cf37b1a9f3fc448a061e</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_bool_t</type>
+ <name>prepared</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>ae5b63fb7d1ac17bfe0f40c1358e2ced2</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>void *</type>
+ <name>mainThreadId</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>a6588fc232f5001c84152098b2fe7695a</anchor>
+ <arglist>[1]</arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>description</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>a8444d6e0dfe2bbab0b5e7b24308f1559</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_transport_cb_f</type>
+ <name>callback</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>ac61a9065fbee4489fa84180893b95ccf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>const void *</type>
+ <name>callback_data</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>a7322346207ed833d5550334332388ff9</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_transport_s::@7</type>
+ <name>tls</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>aa9c46ec1eddafe5714af85e8e3e57169</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_transport_s::@8</type>
+ <name>dtls</name>
+ <anchorfile>structtnet__transport__s.html</anchorfile>
+ <anchor>a72dd4024a92a92e594c56275f2b3d01a</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_allocation_s</name>
+ <filename>structtnet__turn__allocation__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_turn_allocation_id_t</type>
+ <name>id</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a03aaf241a003d900555e758014c83005</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>relay_address</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>ad328f54cea8a7008376efcb17f465d43</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_attribute_mapped_addr_t *</type>
+ <name>maddr</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a1bb895a0f6e6fbe93ac0bc346bc52526</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_attribute_xmapped_addr_t *</type>
+ <name>xmaddr</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a5405872105ef7f32cabddc425993f69a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_fd_t</type>
+ <name>localFD</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a2f7fda9a08aade674a360b301268cd92</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_socket_type_t</type>
+ <name>socket_type</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a27db52c3553ad7f3a50a3f846128f5f3</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct sockaddr_storage</type>
+ <name>server</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>acbcb80535e518b7b9f636338f948b88c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>username</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a9b20c006bd90a09e1465fb668700e81d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>password</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a59460a3ff2c12443d1022e5cc0fba85c</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>realm</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a78e609bc32bd5a9820209fe62b39963f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>nonce</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a814af5af8d9ea73885c8216c0e547e2a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>timeout</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>ab5627d8d8b095c198e2523c44ca380ac</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>char *</type>
+ <name>software</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>ab7dea44af93feeae91fbc350466cd75b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_turn_channel_bindings_L_t *</type>
+ <name>channel_bindings</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>ac6f07a52b24bd7a43b9cef1654b7c2cc</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_turn_permissions_L_t *</type>
+ <name>permissions</name>
+ <anchorfile>structtnet__turn__allocation__s.html</anchorfile>
+ <anchor>a9c680afbc7b9cda04536e1a7a4d25a11</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_attribute_channelnum_s</name>
+ <filename>structtnet__turn__attribute__channelnum__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__turn__attribute__channelnum__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>number</name>
+ <anchorfile>structtnet__turn__attribute__channelnum__s.html</anchorfile>
+ <anchor>adf69c46b3dd2878c66bab78eddc40b04</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>rffu</name>
+ <anchorfile>structtnet__turn__attribute__channelnum__s.html</anchorfile>
+ <anchor>a423dae59c5f12250dfcf3cc92aa1dd06</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_attribute_data_s</name>
+ <filename>structtnet__turn__attribute__data__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__turn__attribute__data__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tsk_buffer_t *</type>
+ <name>value</name>
+ <anchorfile>structtnet__turn__attribute__data__s.html</anchorfile>
+ <anchor>a9bcf56196da97bfeb9b5411f2a5e07f6</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_attribute_dontfrag_s</name>
+ <filename>structtnet__turn__attribute__dontfrag__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__turn__attribute__dontfrag__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_attribute_even_port_s</name>
+ <filename>structtnet__turn__attribute__even__port__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__turn__attribute__even__port__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>R</name>
+ <anchorfile>structtnet__turn__attribute__even__port__s.html</anchorfile>
+ <anchor>ad6607ab22ad9d395773e899a3594bad8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>unsigned</type>
+ <name>rffu</name>
+ <anchorfile>structtnet__turn__attribute__even__port__s.html</anchorfile>
+ <anchor>a80faf1f85f4fda0fad2c1c69903c33dc</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_attribute_lifetime_s</name>
+ <filename>structtnet__turn__attribute__lifetime__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__turn__attribute__lifetime__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>value</name>
+ <anchorfile>structtnet__turn__attribute__lifetime__s.html</anchorfile>
+ <anchor>ae7f66047e6e39ba2bb6af8b95f00d1dd</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_attribute_reqtrans_s</name>
+ <filename>structtnet__turn__attribute__reqtrans__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__turn__attribute__reqtrans__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_proto_t</type>
+ <name>protocol</name>
+ <anchorfile>structtnet__turn__attribute__reqtrans__s.html</anchorfile>
+ <anchor>a8710e9ef6114f67bcc2651eca8a2c7fe</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>rffu</name>
+ <anchorfile>structtnet__turn__attribute__reqtrans__s.html</anchorfile>
+ <anchor>a05893d2921be797904cdd2bf010deef8</anchor>
+ <arglist>[3]</arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_attribute_restoken_s</name>
+ <filename>structtnet__turn__attribute__restoken__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__turn__attribute__restoken__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>value</name>
+ <anchorfile>structtnet__turn__attribute__restoken__s.html</anchorfile>
+ <anchor>ac7a8beb4da4fc8eb8acfec13711a134f</anchor>
+ <arglist>[8]</arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_attribute_xpeer_addr_s</name>
+ <filename>structtnet__turn__attribute__xpeer__addr__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__turn__attribute__xpeer__addr__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_addr_family_t</type>
+ <name>family</name>
+ <anchorfile>structtnet__turn__attribute__xpeer__addr__s.html</anchorfile>
+ <anchor>a49f24db0b2265a9d515199d570dd4e38</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>xport</name>
+ <anchorfile>structtnet__turn__attribute__xpeer__addr__s.html</anchorfile>
+ <anchor>ac021791c2ad249b108a5155d4c252a9f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>xaddress</name>
+ <anchorfile>structtnet__turn__attribute__xpeer__addr__s.html</anchorfile>
+ <anchor>ac365f9f3b4cedc84224afd91b2597ccb</anchor>
+ <arglist>[16]</arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_attribute_xrelayed_addr_s</name>
+ <filename>structtnet__turn__attribute__xrelayed__addr__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TNET_STUN_DECLARE_ATTRIBUTE</name>
+ <anchorfile>structtnet__turn__attribute__xrelayed__addr__s.html</anchorfile>
+ <anchor>a1c1589f58715cc05bb80c012d5979003</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_stun_addr_family_t</type>
+ <name>family</name>
+ <anchorfile>structtnet__turn__attribute__xrelayed__addr__s.html</anchorfile>
+ <anchor>a49f24db0b2265a9d515199d570dd4e38</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>xport</name>
+ <anchorfile>structtnet__turn__attribute__xrelayed__addr__s.html</anchorfile>
+ <anchor>ac021791c2ad249b108a5155d4c252a9f</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint8_t</type>
+ <name>xaddress</name>
+ <anchorfile>structtnet__turn__attribute__xrelayed__addr__s.html</anchorfile>
+ <anchor>ac365f9f3b4cedc84224afd91b2597ccb</anchor>
+ <arglist>[16]</arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_channel_binding_s</name>
+ <filename>structtnet__turn__channel__binding__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__turn__channel__binding__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_turn_channel_binding_id_t</type>
+ <name>id</name>
+ <anchorfile>structtnet__turn__channel__binding__s.html</anchorfile>
+ <anchor>a273d32d05d21a77ad9228c9d1c74c83d</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>struct tnet_turn_allocation_s *</type>
+ <name>allocation</name>
+ <anchorfile>structtnet__turn__channel__binding__s.html</anchorfile>
+ <anchor>a2c19d1b38ea7789b9f45212624c9dfbf</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_turn_attribute_xpeer_addr_t *</type>
+ <name>xpeer</name>
+ <anchorfile>structtnet__turn__channel__binding__s.html</anchorfile>
+ <anchor>af8cae1f1a500edee2f605e5f0396def4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>timeout</name>
+ <anchorfile>structtnet__turn__channel__binding__s.html</anchorfile>
+ <anchor>ab5627d8d8b095c198e2523c44ca380ac</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_channel_data_s</name>
+ <filename>structtnet__turn__channel__data__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__turn__channel__data__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>chanel_number</name>
+ <anchorfile>structtnet__turn__channel__data__s.html</anchorfile>
+ <anchor>aa8c7009bf6b107e3990e62487e1cc7b8</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint16_t</type>
+ <name>length</name>
+ <anchorfile>structtnet__turn__channel__data__s.html</anchorfile>
+ <anchor>a1892eba2086d12ac2b09005aeb09ea3b</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>void *</type>
+ <name>data</name>
+ <anchorfile>structtnet__turn__channel__data__s.html</anchorfile>
+ <anchor>a735984d41155bc1032e09bece8f8d66d</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="struct">
+ <name>tnet_turn_permission_s</name>
+ <filename>structtnet__turn__permission__s.html</filename>
+ <member kind="variable">
+ <type></type>
+ <name>TSK_DECLARE_OBJECT</name>
+ <anchorfile>structtnet__turn__permission__s.html</anchorfile>
+ <anchor>a6cb2c811d40d14ceb34bd3b2e7dc5e6a</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>tnet_turn_attribute_xpeer_addr_t *</type>
+ <name>xpeer</name>
+ <anchorfile>structtnet__turn__permission__s.html</anchorfile>
+ <anchor>af8cae1f1a500edee2f605e5f0396def4</anchor>
+ <arglist></arglist>
+ </member>
+ <member kind="variable">
+ <type>uint32_t</type>
+ <name>timeout</name>
+ <anchorfile>structtnet__turn__permission__s.html</anchorfile>
+ <anchor>ab5627d8d8b095c198e2523c44ca380ac</anchor>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0</name>
+ <path>C:/Projects/doubango/branches/2.0/</path>
+ <filename>dir_23c6058911ec3d6519846acb77914e60.html</filename>
+ <dir>C:/Projects/doubango/branches/2.0/doubango</dir>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches</name>
+ <path>C:/Projects/doubango/branches/</path>
+ <filename>dir_48ccd1e4df20782306b24b8e85052973.html</filename>
+ <dir>C:/Projects/doubango/branches/2.0</dir>
+ </compound>
+ <compound kind="dir">
+ <name>C:</name>
+ <path>C:/</path>
+ <filename>dir_e6bb53534ac0e427887cf7a94c0c004e.html</filename>
+ <dir>C:/Projects</dir>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp/</path>
+ <filename>dir_9305dd5224cc9eb1b74ff189f58e640e.html</filename>
+ <file>tnet_dhcp.c</file>
+ <file>tnet_dhcp.h</file>
+ <file>tnet_dhcp_message.c</file>
+ <file>tnet_dhcp_message.h</file>
+ <file>tnet_dhcp_option.c</file>
+ <file>tnet_dhcp_option.h</file>
+ <file>tnet_dhcp_option_sip.c</file>
+ <file>tnet_dhcp_option_sip.h</file>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6/</path>
+ <filename>dir_eda36b283219a502fc4de8db340bc374.html</filename>
+ <file>tnet_dhcp6.c</file>
+ <file>tnet_dhcp6.h</file>
+ <file>tnet_dhcp6_duid.c</file>
+ <file>tnet_dhcp6_duid.h</file>
+ <file>tnet_dhcp6_message.c</file>
+ <file>tnet_dhcp6_message.h</file>
+ <file>tnet_dhcp6_option.c</file>
+ <file>tnet_dhcp6_option.h</file>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns/</path>
+ <filename>dir_a3af63e0f7dbe4aa673b61a1a0d562c7.html</filename>
+ <file>tnet_dns.c</file>
+ <file>tnet_dns.h</file>
+ <file>tnet_dns_a.c</file>
+ <file>tnet_dns_a.h</file>
+ <file>tnet_dns_aaaa.c</file>
+ <file>tnet_dns_aaaa.h</file>
+ <file>tnet_dns_cname.c</file>
+ <file>tnet_dns_cname.h</file>
+ <file>tnet_dns_message.c</file>
+ <file>tnet_dns_message.h</file>
+ <file>tnet_dns_mx.c</file>
+ <file>tnet_dns_mx.h</file>
+ <file>tnet_dns_naptr.c</file>
+ <file>tnet_dns_naptr.h</file>
+ <file>tnet_dns_ns.c</file>
+ <file>tnet_dns_ns.h</file>
+ <file>tnet_dns_opt.c</file>
+ <file>tnet_dns_opt.h</file>
+ <file>tnet_dns_ptr.c</file>
+ <file>tnet_dns_ptr.h</file>
+ <file>tnet_dns_regexp.c</file>
+ <file>tnet_dns_regexp.h</file>
+ <file>tnet_dns_resolvconf.c</file>
+ <file>tnet_dns_resolvconf.h</file>
+ <file>tnet_dns_rr.c</file>
+ <file>tnet_dns_rr.h</file>
+ <file>tnet_dns_soa.c</file>
+ <file>tnet_dns_soa.h</file>
+ <file>tnet_dns_srv.c</file>
+ <file>tnet_dns_srv.h</file>
+ <file>tnet_dns_txt.c</file>
+ <file>tnet_dns_txt.h</file>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0/doubango</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/</path>
+ <filename>dir_794c5f3a5871fccbd9cb0144b8a918bb.html</filename>
+ <dir>C:/Projects/doubango/branches/2.0/doubango/tinyNET</dir>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango</name>
+ <path>C:/Projects/doubango/</path>
+ <filename>dir_61caa8c9c937953110cbb688168e4704.html</filename>
+ <dir>C:/Projects/doubango/branches</dir>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice/</path>
+ <filename>dir_7326b0f9d77a7a21c8e0c28502dde551.html</filename>
+ <file>tnet_ice.c</file>
+ <file>tnet_ice.h</file>
+ <file>tnet_ice_candidate.c</file>
+ <file>tnet_ice_candidate.h</file>
+ <file>tnet_ice_ctx.c</file>
+ <file>tnet_ice_ctx.h</file>
+ <file>tnet_ice_event.c</file>
+ <file>tnet_ice_event.h</file>
+ <file>tnet_ice_pair.c</file>
+ <file>tnet_ice_pair.h</file>
+ <file>tnet_ice_utils.c</file>
+ <file>tnet_ice_utils.h</file>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects</name>
+ <path>C:/Projects/</path>
+ <filename>dir_e27f7acb6c354cea3d58335de45d9d79.html</filename>
+ <dir>C:/Projects/doubango</dir>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/</path>
+ <filename>dir_dc29ffbc5ac5e8d81dc8895f583aaf87.html</filename>
+ <dir>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp</dir>
+ <dir>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dhcp6</dir>
+ <dir>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/dns</dir>
+ <dir>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/ice</dir>
+ <dir>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/stun</dir>
+ <dir>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/tls</dir>
+ <dir>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/turn</dir>
+ <file>tinynet.h</file>
+ <file>tinynet_config.h</file>
+ <file>tnet.c</file>
+ <file>tnet.h</file>
+ <file>tnet_auth.c</file>
+ <file>tnet_auth.h</file>
+ <file>tnet_endianness.c</file>
+ <file>tnet_endianness.h</file>
+ <file>tnet_hardwares.h</file>
+ <file>tnet_nat.c</file>
+ <file>tnet_nat.h</file>
+ <file>tnet_poll.c</file>
+ <file>tnet_poll.h</file>
+ <file>tnet_proto.h</file>
+ <file>tnet_socket.c</file>
+ <file>tnet_socket.h</file>
+ <file>tnet_transport.c</file>
+ <file>tnet_transport.h</file>
+ <file>tnet_transport_cfsocket.c</file>
+ <file>tnet_transport_poll.c</file>
+ <file>tnet_transport_win32.c</file>
+ <file>tnet_types.h</file>
+ <file>tnet_utils.c</file>
+ <file>tnet_utils.h</file>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/stun</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/stun/</path>
+ <filename>dir_a019e49c2167974a97bc9931fdf595ee.html</filename>
+ <file>tnet_stun.c</file>
+ <file>tnet_stun.h</file>
+ <file>tnet_stun_attribute.c</file>
+ <file>tnet_stun_attribute.h</file>
+ <file>tnet_stun_message.c</file>
+ <file>tnet_stun_message.h</file>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0/doubango/tinyNET</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/</path>
+ <filename>dir_a96db63cb14938079dd27e1b49770c9d.html</filename>
+ <dir>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src</dir>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/tls</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/tls/</path>
+ <filename>dir_6ce67df634907730bdb278977e2dcad6.html</filename>
+ <file>tnet_dtls.c</file>
+ <file>tnet_dtls.h</file>
+ <file>tnet_tls.c</file>
+ <file>tnet_tls.h</file>
+ </compound>
+ <compound kind="dir">
+ <name>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/turn</name>
+ <path>C:/Projects/doubango/branches/2.0/doubango/tinyNET/src/turn/</path>
+ <filename>dir_a624ddd92b7822975b22b7ff89b4a0f7.html</filename>
+ <file>tnet_turn.c</file>
+ <file>tnet_turn.h</file>
+ <file>tnet_turn_attribute.c</file>
+ <file>tnet_turn_attribute.h</file>
+ <file>tnet_turn_message.c</file>
+ <file>tnet_turn_message.h</file>
+ </compound>
+ <compound kind="page">
+ <name>index</name>
+ <title>tinyNET API Overview</title>
+ <filename>index</filename>
+ </compound>
+</tagfile>
diff --git a/tinyNET/tinyNET.vcproj b/tinyNET/tinyNET.vcproj
new file mode 100644
index 0000000..bf930bd
--- /dev/null
+++ b/tinyNET/tinyNET.vcproj
@@ -0,0 +1,732 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="tinyNET"
+ ProjectGUID="{7522A458-92F4-4259-B906-E84C2A65D9F1}"
+ RootNamespace="tinyNET"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="src;..\thirdparties\win32\include;..\thirdparties\common\include;..\tinySAK\src"
+ PreprocessorDefinitions="DEBUG_LEVEL=DEBUG_LEVEL_INFO;HAVE_OPENSSL=1;WIN32;_WIN32_WINNT=0x0501;_DEBUG;_WINDOWS;_USRDLL;TINYNET_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib IPHLPAPI.lib &quot;$(OutDir)\tinySAK.lib&quot; &quot;..\thirdparties\win32\lib\openssl\libeay32.lib&quot; &quot;..\thirdparties\win32\lib\openssl\ssleay32.lib&quot;"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="src;..\thirdparties\win32\include;..\thirdparties\common\include;..\tinySAK\src"
+ PreprocessorDefinitions="DEBUG_LEVEL=DEBUG_LEVEL_ERROR;HAVE_OPENSSL=1;WIN32;_WIN32_WINNT=0x0501;NDEBUG;_WINDOWS;_USRDLL;TINYNET_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ WarnAsError="true"
+ DebugInformationFormat="0"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib IPHLPAPI.lib &quot;$(OutDir)\tinySAK.lib&quot; &quot;..\thirdparties\win32\lib\openssl\libeay32.lib&quot; &quot;..\thirdparties\win32\lib\openssl\ssleay32.lib&quot;"
+ LinkIncremental="1"
+ IgnoreDefaultLibraryNames="MSVCRTD"
+ GenerateDebugInformation="false"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="source(*.c)"
+ >
+ <File
+ RelativePath=".\src\tnet.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_auth.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_endianness.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_nat.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_poll.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_proxy_node_socks_plugin.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_proxy_plugin.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_proxydetect.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_socket.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_transport.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_transport_cfsocket.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_transport_poll.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_transport_win32.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_utils.c"
+ >
+ </File>
+ <Filter
+ Name="stun"
+ >
+ <File
+ RelativePath=".\src\stun\tnet_stun.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_attr.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_attribute.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_binding.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_message.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_pkt.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_utils.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="turn"
+ >
+ <File
+ RelativePath=".\src\turn\tnet_turn.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\turn\tnet_turn_attr.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\turn\tnet_turn_attribute.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\turn\tnet_turn_message.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\turn\tnet_turn_session.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="ice"
+ >
+ <File
+ RelativePath=".\src\ice\tnet_ice_candidate.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ice\tnet_ice_ctx.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ice\tnet_ice_event.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ice\tnet_ice_pair.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ice\tnet_ice_utils.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="dns"
+ >
+ <File
+ RelativePath=".\src\dns\tnet_dns.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_a.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_aaaa.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_cname.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_message.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_mx.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_naptr.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_ns.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_opt.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_ptr.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_regexp.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_resolvconf.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_rr.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_soa.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_srv.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_txt.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="dhcp4"
+ >
+ <File
+ RelativePath=".\src\dhcp\tnet_dhcp.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp\tnet_dhcp_message.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp\tnet_dhcp_option.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp\tnet_dhcp_option_sip.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="dhcp6"
+ >
+ <File
+ RelativePath=".\src\dhcp6\tnet_dhcp6.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp6\tnet_dhcp6_duid.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp6\tnet_dhcp6_message.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp6\tnet_dhcp6_option.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="tls"
+ >
+ <File
+ RelativePath=".\src\tls\tnet_dtls.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tls\tnet_tls.c"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="include(*.h)"
+ >
+ <File
+ RelativePath=".\src\tinynet.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tinynet_config.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_auth.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_endianness.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_hardwares.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_nat.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_poll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_proto.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_proxy_node_socks_plugin.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_proxy_plugin.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_proxydetect.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_socket.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_transport.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_types.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tnet_utils.h"
+ >
+ </File>
+ <Filter
+ Name="stun"
+ >
+ <File
+ RelativePath=".\src\stun\tnet_stun.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_attr.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_attribute.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_binding.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_message.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_pkt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_types.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\stun\tnet_stun_utils.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="turn"
+ >
+ <File
+ RelativePath=".\src\turn\tnet_turn.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\turn\tnet_turn_attr.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\turn\tnet_turn_attribute.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\turn\tnet_turn_message.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\turn\tnet_turn_session.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="ice"
+ >
+ <File
+ RelativePath=".\src\ice\tnet_ice_candidate.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ice\tnet_ice_ctx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ice\tnet_ice_event.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ice\tnet_ice_pair.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ice\tnet_ice_utils.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="dns"
+ >
+ <File
+ RelativePath=".\src\dns\tnet_dns.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_a.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_aaaa.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_cname.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_message.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_mx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_naptr.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_ns.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_opt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_ptr.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_regexp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_resolvconf.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_rr.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_soa.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_srv.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dns\tnet_dns_txt.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="dhcp"
+ >
+ <File
+ RelativePath=".\src\dhcp\tnet_dhcp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp\tnet_dhcp_message.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp\tnet_dhcp_option.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp\tnet_dhcp_option_sip.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="dhcp6"
+ >
+ <File
+ RelativePath=".\src\dhcp6\tnet_dhcp6.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp6\tnet_dhcp6_duid.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp6\tnet_dhcp6_message.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\dhcp6\tnet_dhcp6_option.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="tls"
+ >
+ <File
+ RelativePath=".\src\tls\tnet_dtls.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tls\tnet_tls.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="ragel(.rl)"
+ >
+ <File
+ RelativePath=".\ragel\tnet_dns_regexp.rl"
+ >
+ </File>
+ <File
+ RelativePath=".\ragel\tnet_dns_resolvconf.rl"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="resources(*.rc)"
+ >
+ <File
+ RelativePath=".\version.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/tinyNET/version.rc b/tinyNET/version.rc
new file mode 100644
index 0000000..521e468
--- /dev/null
+++ b/tinyNET/version.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+// #include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 2.0.0.1156
+ PRODUCTVERSION 2.0.0.1156
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Doubango telecom"
+ VALUE "FileDescription", "Doubango IMS Framework"
+ VALUE "FileVersion", "2.0.0.1156"
+ VALUE "InternalName", "tinynet.dll"
+ VALUE "LegalCopyright", "(c) 2010-2013 Doubango Telecom. All rights reserved."
+ VALUE "OriginalFilename", "tinynet.dll"
+ VALUE "ProductName", "Doubango IMS Framework"
+ VALUE "ProductVersion", "2.0.0.1156"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/tinyNET/winrt/tinyNET.sln b/tinyNET/winrt/tinyNET.sln
new file mode 100644
index 0000000..17c0217
--- /dev/null
+++ b/tinyNET/winrt/tinyNET.sln
@@ -0,0 +1,39 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Express 2012 for Windows Phone
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyNET", "tinyNET.vcxproj", "{06E58F9D-28A1-4DD4-AF11-2F5239222CCC}"
+ ProjectSection(ProjectDependencies) = postProject
+ {19279F5B-CDAF-4187-9F09-2A896A828B05} = {19279F5B-CDAF-4187-9F09-2A896A828B05}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinySAK", "..\..\tinySAK\winrt\tinySAK.vcxproj", "{19279F5B-CDAF-4187-9F09-2A896A828B05}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|Win32 = Debug|Win32
+ Release|ARM = Release|ARM
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Debug|ARM.ActiveCfg = Debug|ARM
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Debug|ARM.Build.0 = Debug|ARM
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Debug|Win32.Build.0 = Debug|Win32
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Release|ARM.ActiveCfg = Release|ARM
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Release|ARM.Build.0 = Release|ARM
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Release|Win32.ActiveCfg = Release|Win32
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Release|Win32.Build.0 = Release|Win32
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Debug|ARM.ActiveCfg = Debug|ARM
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Debug|ARM.Build.0 = Debug|ARM
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Debug|Win32.ActiveCfg = Debug|Win32
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Debug|Win32.Build.0 = Debug|Win32
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Release|ARM.ActiveCfg = Release|ARM
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Release|ARM.Build.0 = Release|ARM
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Release|Win32.ActiveCfg = Release|Win32
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tinyNET/winrt/tinyNET.vcxproj b/tinyNET/winrt/tinyNET.vcxproj
new file mode 100644
index 0000000..fac7eb9
--- /dev/null
+++ b/tinyNET/winrt/tinyNET.vcxproj
@@ -0,0 +1,273 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|ARM">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM">
+ <Configuration>Release</Configuration>
+ <Platform>ARM</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{06e58f9d-28a1-4dd4-af11-2f5239222ccc}</ProjectGuid>
+ <RootNamespace>tinyNET</RootNamespace>
+ <DefaultLanguage>en-US</DefaultLanguage>
+ <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110_wp80</PlatformToolset>
+ <IgnoreImportLibrary>false</IgnoreImportLibrary>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110_wp80</PlatformToolset>
+ <IgnoreImportLibrary>false</IgnoreImportLibrary>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v110_wp80</PlatformToolset>
+ <IgnoreImportLibrary>false</IgnoreImportLibrary>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v110_wp80</PlatformToolset>
+ <IgnoreImportLibrary>false</IgnoreImportLibrary>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <GenerateManifest>false</GenerateManifest>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(SolutionDir)$(Configuration)\$(MSBuildProjectName)\</OutDir>
+ <IntDir>$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(SolutionDir)$(Configuration)\$(MSBuildProjectName)\</OutDir>
+ <IntDir>$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+ <OutDir>$(SolutionDir)$(Configuration)\$(MSBuildProjectName)\</OutDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+ <OutDir>$(SolutionDir)$(Configuration)\$(MSBuildProjectName)\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>_USRDLL;TINYNET_EXPORTS;DEBUG_LEVEL=DEBUG_LEVEL_INFO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <CompileAsWinRT>false</CompileAsWinRT>
+ <AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalIncludeDirectories>..\src;..\..\thirdparties\win32\include;..\..\tinySAK\src</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>ws2_32.lib;"$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>_USRDLL;TINYNET_EXPORTS;DEBUG_LEVEL=DEBUG_LEVEL_INFO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <CompileAsWinRT>false</CompileAsWinRT>
+ <AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalIncludeDirectories>..\src;..\..\thirdparties\win32\include;..\..\tinySAK\src</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>ws2_32.lib;"$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+ <ClCompile>
+ <PreprocessorDefinitions>_USRDLL;TINYNET_EXPORTS;DEBUG_LEVEL=DEBUG_LEVEL_INFO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>
+ </PrecompiledHeaderFile>
+ <CompileAsWinRT>false</CompileAsWinRT>
+ <AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalIncludeDirectories>..\src;..\..\thirdparties\win32\include;..\..\tinySAK\src</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>ws2_32.lib;"$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+ <ClCompile>
+ <PreprocessorDefinitions>_USRDLL;TINYNET_EXPORTS;DEBUG_LEVEL=DEBUG_LEVEL_INFO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <CompileAsWinRT>false</CompileAsWinRT>
+ <AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalIncludeDirectories>..\src;..\..\thirdparties\win32\include;..\..\tinySAK\src</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>ws2_32.lib;"$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Reference Include="Windows">
+ <IsWinMDFile>true</IsWinMDFile>
+ </Reference>
+ <Reference Include="platform.winmd">
+ <IsWinMDFile>true</IsWinMDFile>
+ <Private>false</Private>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\src\dhcp6\tnet_dhcp6.c" />
+ <ClCompile Include="..\src\dhcp6\tnet_dhcp6_duid.c" />
+ <ClCompile Include="..\src\dhcp6\tnet_dhcp6_message.c" />
+ <ClCompile Include="..\src\dhcp6\tnet_dhcp6_option.c" />
+ <ClCompile Include="..\src\dhcp\tnet_dhcp.c" />
+ <ClCompile Include="..\src\dhcp\tnet_dhcp_message.c" />
+ <ClCompile Include="..\src\dhcp\tnet_dhcp_option.c" />
+ <ClCompile Include="..\src\dhcp\tnet_dhcp_option_sip.c" />
+ <ClCompile Include="..\src\dns\tnet_dns.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_a.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_aaaa.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_cname.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_message.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_mx.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_naptr.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_ns.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_opt.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_ptr.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_regexp.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_resolvconf.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_rr.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_soa.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_srv.c" />
+ <ClCompile Include="..\src\dns\tnet_dns_txt.c" />
+ <ClCompile Include="..\src\ice\tnet_ice.c" />
+ <ClCompile Include="..\src\ice\tnet_ice_candidate.c" />
+ <ClCompile Include="..\src\ice\tnet_ice_ctx.c" />
+ <ClCompile Include="..\src\ice\tnet_ice_event.c" />
+ <ClCompile Include="..\src\ice\tnet_ice_pair.c" />
+ <ClCompile Include="..\src\ice\tnet_ice_utils.c" />
+ <ClCompile Include="..\src\stun\tnet_stun.c" />
+ <ClCompile Include="..\src\stun\tnet_stun_attribute.c" />
+ <ClCompile Include="..\src\stun\tnet_stun_message.c" />
+ <ClCompile Include="..\src\tls\tnet_dtls.c" />
+ <ClCompile Include="..\src\tls\tnet_tls.c" />
+ <ClCompile Include="..\src\tnet.c" />
+ <ClCompile Include="..\src\tnet_auth.c" />
+ <ClCompile Include="..\src\tnet_endianness.c" />
+ <ClCompile Include="..\src\tnet_nat.c" />
+ <ClCompile Include="..\src\tnet_poll.c" />
+ <ClCompile Include="..\src\tnet_socket.c" />
+ <ClCompile Include="..\src\tnet_transport.c" />
+ <ClCompile Include="..\src\tnet_transport_cfsocket.c" />
+ <ClCompile Include="..\src\tnet_transport_poll.c" />
+ <ClCompile Include="..\src\tnet_transport_win32.c" />
+ <ClCompile Include="..\src\tnet_utils.c">
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">CompileAsCpp</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">CompileAsCpp</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">CompileAsCpp</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">CompileAsCpp</CompileAs>
+ <MinimalRebuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">false</MinimalRebuild>
+ <MinimalRebuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</MinimalRebuild>
+ <CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</CompileAsWinRT>
+ <CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</CompileAsWinRT>
+ <CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</CompileAsWinRT>
+ <CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</CompileAsWinRT>
+ </ClCompile>
+ <ClCompile Include="..\src\turn\tnet_turn.c" />
+ <ClCompile Include="..\src\turn\tnet_turn_attribute.c" />
+ <ClCompile Include="..\src\turn\tnet_turn_message.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\src\dhcp6\tnet_dhcp6.h" />
+ <ClInclude Include="..\src\dhcp6\tnet_dhcp6_duid.h" />
+ <ClInclude Include="..\src\dhcp6\tnet_dhcp6_message.h" />
+ <ClInclude Include="..\src\dhcp6\tnet_dhcp6_option.h" />
+ <ClInclude Include="..\src\dhcp\tnet_dhcp.h" />
+ <ClInclude Include="..\src\dhcp\tnet_dhcp_message.h" />
+ <ClInclude Include="..\src\dhcp\tnet_dhcp_option.h" />
+ <ClInclude Include="..\src\dhcp\tnet_dhcp_option_sip.h" />
+ <ClInclude Include="..\src\dns\tnet_dns.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_a.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_aaaa.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_cname.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_message.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_mx.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_naptr.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_ns.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_opt.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_ptr.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_regexp.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_resolvconf.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_rr.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_soa.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_srv.h" />
+ <ClInclude Include="..\src\dns\tnet_dns_txt.h" />
+ <ClInclude Include="..\src\ice\tnet_ice.h" />
+ <ClInclude Include="..\src\ice\tnet_ice_candidate.h" />
+ <ClInclude Include="..\src\ice\tnet_ice_ctx.h" />
+ <ClInclude Include="..\src\ice\tnet_ice_event.h" />
+ <ClInclude Include="..\src\ice\tnet_ice_pair.h" />
+ <ClInclude Include="..\src\ice\tnet_ice_utils.h" />
+ <ClInclude Include="..\src\stun\tnet_stun.h" />
+ <ClInclude Include="..\src\stun\tnet_stun_attribute.h" />
+ <ClInclude Include="..\src\stun\tnet_stun_message.h" />
+ <ClInclude Include="..\src\tinynet.h" />
+ <ClInclude Include="..\src\tinynet_config.h" />
+ <ClInclude Include="..\src\tls\tnet_dtls.h" />
+ <ClInclude Include="..\src\tls\tnet_tls.h" />
+ <ClInclude Include="..\src\tnet.h" />
+ <ClInclude Include="..\src\tnet_auth.h" />
+ <ClInclude Include="..\src\tnet_endianness.h" />
+ <ClInclude Include="..\src\tnet_hardwares.h" />
+ <ClInclude Include="..\src\tnet_nat.h" />
+ <ClInclude Include="..\src\tnet_poll.h" />
+ <ClInclude Include="..\src\tnet_proto.h" />
+ <ClInclude Include="..\src\tnet_socket.h" />
+ <ClInclude Include="..\src\tnet_transport.h" />
+ <ClInclude Include="..\src\tnet_types.h" />
+ <ClInclude Include="..\src\tnet_utils.h" />
+ <ClInclude Include="..\src\turn\tnet_turn.h" />
+ <ClInclude Include="..\src\turn\tnet_turn_attribute.h" />
+ <ClInclude Include="..\src\turn\tnet_turn_message.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsPhone\v$(TargetPlatformVersion)\Microsoft.Cpp.WindowsPhone.$(TargetPlatformVersion).targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/tinyNET/winrt/tinyNET.vcxproj.filters b/tinyNET/winrt/tinyNET.vcxproj.filters
new file mode 100644
index 0000000..c718e80
--- /dev/null
+++ b/tinyNET/winrt/tinyNET.vcxproj.filters
@@ -0,0 +1,361 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="src">
+ <UniqueIdentifier>{47f38206-11cf-484b-bb21-41f9fc8ad1e7}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include">
+ <UniqueIdentifier>{487af1d7-a6a5-4e50-aa56-3e93a4b1af2b}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\dhcp">
+ <UniqueIdentifier>{823fe823-12d9-4e4d-ab93-c5133352f255}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\dhcp6">
+ <UniqueIdentifier>{cb7d0bec-d40a-400b-8eb9-5997db656b63}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\dns">
+ <UniqueIdentifier>{9ccf87f0-6e7f-4c8d-91f1-74575af88fa3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\ice">
+ <UniqueIdentifier>{282952bf-02ca-4eaf-8200-6ac829dbdff3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\stun">
+ <UniqueIdentifier>{665f9d4d-326f-43d9-8c69-e41082a796bf}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\tls">
+ <UniqueIdentifier>{79d8933a-c689-418c-a94f-a5c0f034ea06}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\turn">
+ <UniqueIdentifier>{64ea99a0-485d-49e2-ad73-b537d2684891}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\dhcp">
+ <UniqueIdentifier>{b2cde3ed-acb7-44c9-a22f-0d5c8778bbf2}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\dhcp6">
+ <UniqueIdentifier>{3c2e591f-39ec-4dde-adee-c8f23a35a2f1}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\dns">
+ <UniqueIdentifier>{7719f54d-3ff7-44c7-8e00-333ad4e25f8a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\ice">
+ <UniqueIdentifier>{7ba51cd7-7828-4a91-b613-34050785d8b6}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\stun">
+ <UniqueIdentifier>{12dcf1c9-283d-4abb-b91b-7dcfc913a94c}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\tls">
+ <UniqueIdentifier>{ce5dd118-cde0-4d23-a1b5-ac936cae3834}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\turn">
+ <UniqueIdentifier>{cbbc38d6-4e5e-42dd-9924-1d0c3cc0542f}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\src\tnet.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tnet_endianness.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dhcp\tnet_dhcp.c">
+ <Filter>src\dhcp</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dhcp\tnet_dhcp_message.c">
+ <Filter>src\dhcp</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dhcp\tnet_dhcp_option.c">
+ <Filter>src\dhcp</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dhcp\tnet_dhcp_option_sip.c">
+ <Filter>src\dhcp</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dhcp6\tnet_dhcp6.c">
+ <Filter>src\dhcp6</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dhcp6\tnet_dhcp6_duid.c">
+ <Filter>src\dhcp6</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dhcp6\tnet_dhcp6_message.c">
+ <Filter>src\dhcp6</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dhcp6\tnet_dhcp6_option.c">
+ <Filter>src\dhcp6</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_a.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_aaaa.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_cname.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_message.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_mx.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_naptr.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_ns.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_opt.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_ptr.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_regexp.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_resolvconf.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_rr.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_soa.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_srv.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\dns\tnet_dns_txt.c">
+ <Filter>src\dns</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\ice\tnet_ice.c">
+ <Filter>src\ice</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\ice\tnet_ice_candidate.c">
+ <Filter>src\ice</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\ice\tnet_ice_ctx.c">
+ <Filter>src\ice</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\ice\tnet_ice_event.c">
+ <Filter>src\ice</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\ice\tnet_ice_pair.c">
+ <Filter>src\ice</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\ice\tnet_ice_utils.c">
+ <Filter>src\ice</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\stun\tnet_stun.c">
+ <Filter>src\stun</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\stun\tnet_stun_attribute.c">
+ <Filter>src\stun</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\stun\tnet_stun_message.c">
+ <Filter>src\stun</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tls\tnet_dtls.c">
+ <Filter>src\tls</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tls\tnet_tls.c">
+ <Filter>src\tls</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\turn\tnet_turn.c">
+ <Filter>src\turn</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\turn\tnet_turn_attribute.c">
+ <Filter>src\turn</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\turn\tnet_turn_message.c">
+ <Filter>src\turn</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tnet_auth.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tnet_nat.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tnet_poll.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tnet_socket.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tnet_transport.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tnet_transport_cfsocket.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tnet_transport_poll.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tnet_transport_win32.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tnet_utils.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\src\dhcp\tnet_dhcp.h">
+ <Filter>include\dhcp</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dhcp\tnet_dhcp_message.h">
+ <Filter>include\dhcp</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dhcp\tnet_dhcp_option.h">
+ <Filter>include\dhcp</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dhcp\tnet_dhcp_option_sip.h">
+ <Filter>include\dhcp</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dhcp6\tnet_dhcp6.h">
+ <Filter>include\dhcp6</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dhcp6\tnet_dhcp6_duid.h">
+ <Filter>include\dhcp6</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dhcp6\tnet_dhcp6_message.h">
+ <Filter>include\dhcp6</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dhcp6\tnet_dhcp6_option.h">
+ <Filter>include\dhcp6</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_a.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_aaaa.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_cname.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_message.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_mx.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_naptr.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_ns.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_opt.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_ptr.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_regexp.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_resolvconf.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_rr.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_soa.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_srv.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\dns\tnet_dns_txt.h">
+ <Filter>include\dns</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\ice\tnet_ice.h">
+ <Filter>include\ice</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\ice\tnet_ice_candidate.h">
+ <Filter>include\ice</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\ice\tnet_ice_ctx.h">
+ <Filter>include\ice</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\ice\tnet_ice_event.h">
+ <Filter>include\ice</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\ice\tnet_ice_pair.h">
+ <Filter>include\ice</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\ice\tnet_ice_utils.h">
+ <Filter>include\ice</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\turn\tnet_turn.h">
+ <Filter>include\turn</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\turn\tnet_turn_attribute.h">
+ <Filter>include\turn</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\turn\tnet_turn_message.h">
+ <Filter>include\turn</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tls\tnet_dtls.h">
+ <Filter>include\tls</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tls\tnet_tls.h">
+ <Filter>include\tls</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\stun\tnet_stun.h">
+ <Filter>include\stun</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\stun\tnet_stun_attribute.h">
+ <Filter>include\stun</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\stun\tnet_stun_message.h">
+ <Filter>include\stun</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tinynet.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tinynet_config.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet_auth.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet_endianness.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet_hardwares.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet_nat.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet_poll.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet_proto.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet_socket.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet_transport.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet_types.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\tnet_utils.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
OpenPOWER on IntegriCloud