Bug 790517: Import nICEr library for mtransport rs=biesi,jesup r=gerv
authorEKR <ekr@rtfm.com>
Fri, 21 Sep 2012 07:11:13 -0700
changeset 115855 b5246d1cd36441119421eabd8b196b91aa45a7e1
parent 115854 0dfe80d8fc1da0f13fdef204303d0e8b808b90f5
child 115856 5d59f7ecfb16e04e0660240150f66beb917f51b3
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbiesi, jesup, gerv
bugs790517
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 790517: Import nICEr library for mtransport rs=biesi,jesup r=gerv
media/mtransport/third_party/nICEr/IMPORT_FILES
media/mtransport/third_party/nICEr/README
media/mtransport/third_party/nICEr/README_MOZILLA
media/mtransport/third_party/nICEr/nicer.gyp
media/mtransport/third_party/nICEr/src/crypto/nr_crypto.c
media/mtransport/third_party/nICEr/src/crypto/nr_crypto.h
media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
media/mtransport/third_party/nICEr/src/ice/ice_candidate.h
media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.c
media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.h
media/mtransport/third_party/nICEr/src/ice/ice_codeword.h
media/mtransport/third_party/nICEr/src/ice/ice_component.c
media/mtransport/third_party/nICEr/src/ice/ice_component.h
media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
media/mtransport/third_party/nICEr/src/ice/ice_handler.h
media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
media/mtransport/third_party/nICEr/src/ice/ice_media_stream.h
media/mtransport/third_party/nICEr/src/ice/ice_parser.c
media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.c
media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.h
media/mtransport/third_party/nICEr/src/ice/ice_reg.h
media/mtransport/third_party/nICEr/src/ice/ice_socket.c
media/mtransport/third_party/nICEr/src/ice/ice_socket.h
media/mtransport/third_party/nICEr/src/net/nr_socket.c
media/mtransport/third_party/nICEr/src/net/nr_socket.h
media/mtransport/third_party/nICEr/src/net/nr_socket_local.h
media/mtransport/third_party/nICEr/src/net/transport_addr.c
media/mtransport/third_party/nICEr/src/net/transport_addr.h
media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
media/mtransport/third_party/nICEr/src/net/transport_addr_reg.h
media/mtransport/third_party/nICEr/src/stun/addrs.c
media/mtransport/third_party/nICEr/src/stun/addrs.h
media/mtransport/third_party/nICEr/src/stun/nr_socket_turn.c
media/mtransport/third_party/nICEr/src/stun/nr_socket_turn.h
media/mtransport/third_party/nICEr/src/stun/stun.h
media/mtransport/third_party/nICEr/src/stun/stun_build.c
media/mtransport/third_party/nICEr/src/stun/stun_build.h
media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c
media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.h
media/mtransport/third_party/nICEr/src/stun/stun_codec.c
media/mtransport/third_party/nICEr/src/stun/stun_codec.h
media/mtransport/third_party/nICEr/src/stun/stun_hint.c
media/mtransport/third_party/nICEr/src/stun/stun_hint.h
media/mtransport/third_party/nICEr/src/stun/stun_msg.c
media/mtransport/third_party/nICEr/src/stun/stun_msg.h
media/mtransport/third_party/nICEr/src/stun/stun_proc.c
media/mtransport/third_party/nICEr/src/stun/stun_proc.h
media/mtransport/third_party/nICEr/src/stun/stun_reg.h
media/mtransport/third_party/nICEr/src/stun/stun_server_ctx.c
media/mtransport/third_party/nICEr/src/stun/stun_server_ctx.h
media/mtransport/third_party/nICEr/src/stun/stun_util.c
media/mtransport/third_party/nICEr/src/stun/stun_util.h
media/mtransport/third_party/nICEr/src/stun/turn_client_ctx.c
media/mtransport/third_party/nICEr/src/stun/turn_client_ctx.h
media/mtransport/third_party/nICEr/src/util/cb_args.c
media/mtransport/third_party/nICEr/src/util/cb_args.h
media/mtransport/third_party/nICEr/src/util/ice_util.c
media/mtransport/third_party/nICEr/src/util/ice_util.h
media/mtransport/third_party/nICEr/src/util/mbslen.c
media/mtransport/third_party/nICEr/src/util/mbslen.h
media/mtransport/third_party/nICEr/upstream.diff
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/IMPORT_FILES
@@ -0,0 +1,69 @@
+                # Crypto
+                ./src/crypto/nr_crypto.c
+                ./src/crypto/nr_crypto.h
+                #./src/crypto/nr_crypto_openssl.c
+                #./src/crypto/nr_crypto_openssl.h
+
+                # ICE
+                ./src/ice/ice_candidate.c
+                ./src/ice/ice_candidate.h
+                ./src/ice/ice_candidate_pair.c
+                ./src/ice/ice_candidate_pair.h
+                ./src/ice/ice_codeword.h
+                ./src/ice/ice_component.c
+                ./src/ice/ice_component.h
+                ./src/ice/ice_ctx.c
+                ./src/ice/ice_ctx.h
+                ./src/ice/ice_handler.h
+                ./src/ice/ice_media_stream.c
+                ./src/ice/ice_media_stream.h
+                ./src/ice/ice_parser.c
+                ./src/ice/ice_peer_ctx.c
+                ./src/ice/ice_peer_ctx.h
+                ./src/ice/ice_reg.h
+                ./src/ice/ice_socket.c
+                ./src/ice/ice_socket.h
+
+                # Net
+                ./src/net/nr_socket.c
+                ./src/net/nr_socket.h
+                #./src/net/nr_socket_local.c
+                ./src/net/nr_socket_local.h
+                ./src/net/transport_addr.c
+                ./src/net/transport_addr.h
+                ./src/net/transport_addr_reg.c
+                ./src/net/transport_addr_reg.h
+
+                # STUN
+                ./src/stun/addrs.c
+                ./src/stun/addrs.h
+                ./src/stun/nr_socket_turn.c
+                ./src/stun/nr_socket_turn.h
+                ./src/stun/stun.h
+                ./src/stun/stun_build.c
+                ./src/stun/stun_build.h
+                ./src/stun/stun_client_ctx.c
+                ./src/stun/stun_client_ctx.h
+                ./src/stun/stun_codec.c
+                ./src/stun/stun_codec.h
+                ./src/stun/stun_hint.c
+                ./src/stun/stun_hint.h
+                ./src/stun/stun_msg.c
+                ./src/stun/stun_msg.h
+                ./src/stun/stun_proc.c
+                ./src/stun/stun_proc.h
+                ./src/stun/stun_reg.h
+                ./src/stun/stun_server_ctx.c
+                ./src/stun/stun_server_ctx.h
+                ./src/stun/stun_util.c
+                ./src/stun/stun_util.h
+                ./src/stun/turn_client_ctx.c
+                ./src/stun/turn_client_ctx.h
+
+                # Util
+                ./src/util/cb_args.c
+                ./src/util/cb_args.h
+                ./src/util/ice_util.c
+                ./src/util/ice_util.h
+                ./src/util/mbslen.c
+                ./src/util/mbslen.h
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/README
@@ -0,0 +1,74 @@
+                             nICEr 1.0
+
+PREREQUISITES:
+-------------
+You must first obtain and build the following packages:
+
+* nrappkit
+  - http://nrappkit.sourceforge.net/
+
+* OpenSSL-0.9.8g
+  - http://www.openssl.org/source/openssl-0.9.8g.tar.gz
+
+
+For best results, the "ice-<version>" directory should be at
+the same level as the "nrappkit" and "openssl-0.9.8g"
+directories.  I.e., the directory structure should look like:
+
+   nrappkit/
+   ice-<version>/
+   openssl/
+          include/
+          lib/VC/
+
+
+BUILDING ON UNIX:
+----------------
+Once the prerequisite packages are built, 'cd' to the
+relevant build directory, one of:
+
+   ice-<version>/make/darwin
+   ice-<version>/make/linux-fedora
+   ice-<version>/make/ubuntu
+
+and simply do a "make".
+
+
+BUILDING ON WINDOWS:
+-------------------
+The Visual C++ project files are configured to expect the
+directory structure described above.
+ 
+Note: Binary Windows builds of OpenSSL can be found at:
+   http://www.slproweb.com/products/Win32OpenSSL.html
+
+Once the prerequisite packages are built, open the VC++ 9.0
+solution file: ICE/make/win32/ice.sln and build the solution.
+Note: Since the VC++ project/solution files are version 9.0,
+Visual Studio 2008 is required.
+
+
+STATUS:
+------
+The ICE code has been tested on the following platforms:
+-- Fedora Core 4 (Intel 32-bit)
+-- Fedora Core 6 (Intel 32-bit)
+-- Ubuntu 6.10 
+-- MacOSX 10.4.9
+-- Windows Vista (Home Premium)
+-- Windows XP Pro
+-- Windows 2000 SP4
+
+
+KNOWN ISSUES:
+------------
+-- TURN SET-ACTIVE-DESTINATION mode not yet supported.
+
+-- Problems may exist with the TURN client implementation; the TURN code
+   has received minimal testing due to the unavailability of a real
+   TURN server to test against.
+
+-- The ICE-Lite implementation is not complete.
+
+-- The new "impatient" timeout has not yet been thoroughly tested.
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/README_MOZILLA
@@ -0,0 +1,11 @@
+This code was imported from:
+
+https://svn.resiprocate.org/rep/resiprocate/main/nICEr
+
+SVN revision 9873
+
+Some minor changes have been made to improve portability as well
+as to add trickle ICE. These changes are being submitted for
+upstreaming and can be found in upstream.diff.
+
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/nicer.gyp
@@ -0,0 +1,212 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# nrappkit.gyp
+#
+#
+{
+  'targets' : [
+      {
+          'target_name' : 'nicer',
+          'type' : 'static_library',
+
+          'include_dirs' : [
+              ## EXTERNAL
+              # nrappkit
+	      '../nrappkit/src/event',
+	      '../nrappkit/src/log',
+              '../nrappkit/src/plugin',
+	      '../nrappkit/src/registry',
+	      '../nrappkit/src/share',
+	      '../nrappkit/src/stats',
+	      '../nrappkit/src/util',
+	      '../nrappkit/src/util/libekr',
+
+              # INTERNAL
+              "./src/crypto",
+              "./src/ice",
+              "./src/net",
+              "./src/stun",
+              "./src/util",
+          ],
+
+          'sources' : [
+                # Crypto
+                "./src/crypto/nr_crypto.c",
+                "./src/crypto/nr_crypto.h",
+                #"./src/crypto/nr_crypto_openssl.c",
+                #"./src/crypto/nr_crypto_openssl.h",
+
+                # ICE
+                "./src/ice/ice_candidate.c",
+                "./src/ice/ice_candidate.h",
+                "./src/ice/ice_candidate_pair.c",
+                "./src/ice/ice_candidate_pair.h",
+                "./src/ice/ice_codeword.h",
+                "./src/ice/ice_component.c",
+                "./src/ice/ice_component.h",
+                "./src/ice/ice_ctx.c",
+                "./src/ice/ice_ctx.h",
+                "./src/ice/ice_handler.h",
+                "./src/ice/ice_media_stream.c",
+                "./src/ice/ice_media_stream.h",
+                "./src/ice/ice_parser.c",
+                "./src/ice/ice_peer_ctx.c",
+                "./src/ice/ice_peer_ctx.h",
+                "./src/ice/ice_reg.h",
+                "./src/ice/ice_socket.c",
+                "./src/ice/ice_socket.h",
+
+                # Net
+                "./src/net/nr_socket.c",
+                "./src/net/nr_socket.h",
+                #"./src/net/nr_socket_local.c",
+                "./src/net/nr_socket_local.h",
+                "./src/net/transport_addr.c",
+                "./src/net/transport_addr.h",
+                "./src/net/transport_addr_reg.c",
+                "./src/net/transport_addr_reg.h",
+
+                # STUN
+                "./src/stun/addrs.c",
+                "./src/stun/addrs.h",
+                "./src/stun/nr_socket_turn.c",
+                "./src/stun/nr_socket_turn.h",
+                "./src/stun/stun.h",
+                "./src/stun/stun_build.c",
+                "./src/stun/stun_build.h",
+                "./src/stun/stun_client_ctx.c",
+                "./src/stun/stun_client_ctx.h",
+                "./src/stun/stun_codec.c",
+                "./src/stun/stun_codec.h",
+                "./src/stun/stun_hint.c",
+                "./src/stun/stun_hint.h",
+                "./src/stun/stun_msg.c",
+                "./src/stun/stun_msg.h",
+                "./src/stun/stun_proc.c",
+                "./src/stun/stun_proc.h",
+                "./src/stun/stun_reg.h",
+                "./src/stun/stun_server_ctx.c",
+                "./src/stun/stun_server_ctx.h",
+                "./src/stun/stun_util.c",
+                "./src/stun/stun_util.h",
+                "./src/stun/turn_client_ctx.c",
+                "./src/stun/turn_client_ctx.h",
+
+                # Util
+                "./src/util/cb_args.c",
+                "./src/util/cb_args.h",
+                "./src/util/ice_util.c",
+                "./src/util/ice_util.h",
+                "./src/util/mbslen.c",
+                "./src/util/mbslen.h",
+
+
+          ],
+          
+          'defines' : [
+              'SANITY_CHECKS',
+              'USE_TURN',
+              'USE_ICE',
+              'USE_RFC_3489_BACKWARDS_COMPATIBLE',
+              'USE_STUND_0_96',
+              'USE_STUN_PEDANTIC',
+              'USE_TURN',
+              'NR_SOCKET_IS_VOID_PTR',
+              'restrict=',
+          ],
+          
+          'conditions' : [
+              ## Mac
+              [ 'OS == "mac"', {
+                'cflags_mozilla': [
+                    '-Werror',
+                    '-Wall',
+                    '-Wno-parentheses',
+                    '-Wno-strict-prototypes',
+                    '-Wmissing-prototypes',
+                 ],
+                 'defines' : [
+                     'DARWIN',
+                     'HAVE_LIBM=1',
+                     'HAVE_STRDUP=1',
+                     'HAVE_STRLCPY=1',
+                     'HAVE_SYS_TIME_H=1',
+                     'HAVE_VFPRINTF=1',
+                     'NEW_STDIO'
+                     'RETSIGTYPE=void',
+                     'TIME_WITH_SYS_TIME_H=1',
+                     '__UNUSED__="__attribute__((unused))"',
+                 ],
+
+		 'include_dirs': [
+		     '../nrappkit/src/port/darwin/include'
+		 ],
+		 
+		 'sources': [
+		 ],
+              }],
+              
+              ## Win
+              [ 'OS == "win"', {
+                'defines' : [
+                    'WIN32',
+                    'USE_ICE',
+                    'USE_TURN',
+                    'USE_RFC_3489_BACKWARDS_COMPATIBLE',
+                    'USE_STUND_0_96',
+                    'USE_STUN_PEDANTIC',
+                    '_CRT_SECURE_NO_WARNINGS',
+                    '__UNUSED__=',
+                    'HAVE_STRDUP',
+                    'SIZEOF_SHORT=2',
+                    'SIZEOF_UNSIGNED_SHORT=2',
+                    'SIZEOF_INT=4',
+                    'SIZEOF_UNSIGNED_INT=4',
+                    'SIZEOF_LONG=4',
+                    'SIZEOF_UNSIGNED_LONG=4',
+                    'SIZEOF_LONG_LONG=8',
+                    'SIZEOF_UNSIGNED_LONG_LONG=8',
+                    'NO_REG_RPC'
+                ],
+
+		 'include_dirs': [
+		     '../nrappkit/src/port/win32/include'
+		 ],
+              }],
+
+              
+              ## Linux
+              [ 'OS == "linux"', {
+                'cflags': [
+                    '-Werror',
+                    '-Wall',
+                    '-Wno-parentheses',
+                    '-Wno-strict-prototypes',
+                    '-Wmissing-prototypes',
+                 ],
+                 'defines' : [
+                     'LINUX',
+                     'HAVE_LIBM=1',
+                     'HAVE_STRDUP=1',
+                     'HAVE_STRLCPY=1',
+                     'HAVE_SYS_TIME_H=1',
+                     'HAVE_VFPRINTF=1',
+                     'NEW_STDIO'
+                     'RETSIGTYPE=void',
+                     'TIME_WITH_SYS_TIME_H=1',
+                     '__UNUSED__="__attribute__((unused))"',
+                 ],
+
+		 'include_dirs': [
+		     '../nrappkit/src/port/linux/include'
+		 ],
+		 
+		 'sources': [
+		 ],
+              }]
+          ]
+      }]
+}
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/crypto/nr_crypto.c
@@ -0,0 +1,63 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: nr_crypto.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
+
+#include <nr_api.h>
+#include "nr_crypto.h"
+
+static int nr_ice_crypto_dummy_random_bytes(UCHAR *buf, int len)
+  {
+    fprintf(stderr,"Need to define crypto API implementation\n");
+
+    exit(1);
+  }
+
+static int nr_ice_crypto_dummy_hmac_sha1(UCHAR *key, int key_l, UCHAR *buf, int buf_l, UCHAR digest[20])
+  {
+    fprintf(stderr,"Need to define crypto API implementation\n");
+
+    exit(1);
+  }
+
+static nr_ice_crypto_vtbl nr_ice_crypto_dummy_vtbl= {
+  nr_ice_crypto_dummy_random_bytes,
+  nr_ice_crypto_dummy_hmac_sha1
+};
+
+
+
+nr_ice_crypto_vtbl *nr_crypto_vtbl=&nr_ice_crypto_dummy_vtbl;
+
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/crypto/nr_crypto.h
@@ -0,0 +1,50 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _nr_crypto_h
+#define _nr_crypto_h
+
+
+typedef struct nr_ice_crypto_vtbl_ {
+  int (*random_bytes)(UCHAR *buf, int len);
+  int (*hmac_sha1)(UCHAR *key, int key_l, UCHAR *buf, int buf_l, UCHAR digest[20]);
+} nr_ice_crypto_vtbl;
+
+extern nr_ice_crypto_vtbl *nr_crypto_vtbl;
+
+#define nr_crypto_random_bytes(a,b) nr_crypto_vtbl->random_bytes(a,b)
+#define nr_crypto_hmac_sha1(a,b,c,d,e) nr_crypto_vtbl->hmac_sha1(a,b,c,d,e)
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -0,0 +1,648 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: ice_candidate.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
+
+#include <csi_platform.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include "nr_api.h"
+#include "registry.h"
+#include "nr_socket.h"
+#include "async_timer.h"
+
+#include "stun_client_ctx.h"
+#include "stun_server_ctx.h"
+#include "turn_client_ctx.h"
+#include "ice_ctx.h"
+#include "ice_candidate.h"
+#include "ice_reg.h"
+#include "ice_util.h"
+#include "nr_socket_turn.h"
+
+static int next_automatic_preference = 224;
+
+static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
+static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg);
+static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
+#ifdef USE_TURN
+static int nr_ice_start_relay_turn(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg);
+static void nr_ice_turn_allocated_cb(NR_SOCKET sock, int how, void *cb_arg);
+#endif /* USE_TURN */
+
+char *nr_ice_candidate_type_names[]={0,"host","srflx","prflx","relay",0};
+
+int nr_ice_candidate_create(nr_ice_ctx *ctx,char *label,nr_ice_component *comp,nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp)
+  {
+    nr_ice_candidate *cand=0;
+    nr_ice_candidate *tmp=0;
+    int r,_status;
+
+    if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
+      ABORT(R_NO_MEMORY);
+    if(!(cand->label=r_strdup(label)))
+      ABORT(R_NO_MEMORY);
+    cand->state=NR_ICE_CAND_STATE_CREATED;
+    cand->ctx=ctx;
+    cand->isock=isock;
+    cand->osock=osock;
+    cand->type=ctype;
+    cand->stun_server=stun_server;
+    cand->component_id=component_id;
+    cand->component=comp;
+    cand->stream=comp->stream;
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): creating candidate %s with type %s",
+      ctx->label,label,nr_ice_candidate_type_names[ctype]);
+
+    /* Extract the addr as the base */
+    if(r=nr_socket_getaddr(cand->isock->sock,&cand->base))
+      ABORT(r);
+    if(r=nr_ice_get_foundation(ctx,cand))
+      ABORT(r);
+    if(r=nr_ice_candidate_compute_priority(cand))
+      ABORT(r);
+
+    TAILQ_FOREACH(tmp,&isock->candidates,entry_sock){
+      if(cand->priority==tmp->priority){
+        r_log(LOG_ICE,LOG_WARNING,"ICE(%s): duplicate priority %u candidate %s and candidate %s",
+          ctx->label,cand->priority,cand->label,tmp->label);
+      }
+    }
+
+    if(ctype==RELAYED)
+      cand->u.relayed.turn_sock=osock;
+
+    /* Add the candidate to the isock list*/
+    TAILQ_INSERT_TAIL(&isock->candidates,cand,entry_sock);
+    
+    *candp=cand;
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+
+
+/* Create a peer reflexive candidate */
+int nr_ice_peer_peer_rflx_candidate_create(nr_ice_ctx *ctx,char *label, nr_ice_component *comp,nr_transport_addr *addr, nr_ice_candidate **candp)
+  {
+    nr_ice_candidate *cand=0;
+    nr_ice_candidate_type ctype=PEER_REFLEXIVE;
+    int r,_status;
+ 
+    if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
+      ABORT(R_NO_MEMORY);
+    if(!(cand->label=r_strdup(label)))
+      ABORT(R_NO_MEMORY);
+
+    cand->state=NR_ICE_CAND_STATE_INITIALIZED;
+    cand->ctx=ctx;
+    cand->type=ctype;
+    cand->component_id=comp->component_id;
+    cand->component=comp;
+    cand->stream=comp->stream;
+
+    
+    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): creating candidate %s with type %d",
+      ctx->label,label,ctype);
+
+    if(r=nr_transport_addr_copy(&cand->base,addr))
+      ABORT(r);
+    if(r=nr_transport_addr_copy(&cand->addr,addr))
+      ABORT(r);
+    /* Bogus foundation */
+    if(!(cand->foundation=r_strdup(cand->addr.as_string)))
+      ABORT(r);
+
+    *candp=cand;
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_candidate_destroy(nr_ice_candidate **candp)
+  {
+    nr_ice_candidate *cand=0;
+
+    if(!candp || !*candp)
+      return(0);
+
+    cand=*candp;
+
+    switch(cand->type){
+      case HOST:
+        break;
+#ifdef USE_TURN
+      case RELAYED:
+        nr_turn_client_ctx_destroy(&cand->u.relayed.turn);
+        nr_socket_destroy(&cand->u.relayed.turn_sock);
+        break;
+#endif /* USE_TURN */
+      case SERVER_REFLEXIVE:
+        break;
+      default:
+        break;
+    }
+
+    if(cand->delay_timer)
+      NR_async_timer_cancel(cand->delay_timer);
+
+    RFREE(cand->foundation);
+    RFREE(cand->label);
+    RFREE(cand);
+    
+    return(0);
+  }
+
+void nr_ice_candidate_destroy_cb(NR_SOCKET s, int h, void *cb_arg)
+  {
+    nr_ice_candidate *cand=cb_arg;
+    nr_ice_candidate_destroy(&cand);
+  }
+
+/* This algorithm is not super-fast, but I don't think we need a hash
+   table just yet and it produces a small foundation string */
+static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand)
+  {
+    nr_ice_foundation *foundation;
+    int i=0;
+    char fnd[20];
+    int _status;
+
+    foundation=STAILQ_FIRST(&ctx->foundations);
+    while(foundation){
+      if(nr_transport_addr_cmp(&cand->base,&foundation->addr,NR_TRANSPORT_ADDR_CMP_MODE_ADDR))
+        goto next;
+      if(cand->type != foundation->type)
+        goto next;
+      if(cand->stun_server != foundation->stun_server)
+        goto next;
+
+      sprintf(fnd,"%d",i);
+      if(!(cand->foundation=r_strdup(fnd)))
+        ABORT(R_NO_MEMORY);
+      return(0);
+
+    next:
+      foundation=STAILQ_NEXT(foundation,entry);
+      i++;
+    }
+
+    if(!(foundation=RCALLOC(sizeof(nr_ice_foundation))))
+      ABORT(R_NO_MEMORY);
+    nr_transport_addr_copy(&foundation->addr,&cand->base);
+    foundation->type=cand->type;
+    foundation->stun_server=cand->stun_server;
+    STAILQ_INSERT_TAIL(&ctx->foundations,foundation,entry);
+
+    sprintf(fnd,"%d",i);
+    if(!(cand->foundation=r_strdup(fnd)))
+      ABORT(R_NO_MEMORY);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_candidate_compute_priority(nr_ice_candidate *cand)
+  {
+    UCHAR type_preference;
+    UCHAR interface_preference;
+    UCHAR stun_priority;
+    int r,_status;
+
+    switch(cand->type){
+      case HOST:
+        if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_HOST,&type_preference))
+          ABORT(r);
+        stun_priority=0;
+        break;
+      case RELAYED:
+        if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED,&type_preference))
+          ABORT(r);
+        stun_priority=255-cand->stun_server->index;
+        break;
+      case SERVER_REFLEXIVE:
+        if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_SRV_RFLX,&type_preference))
+          ABORT(r);
+        stun_priority=255-cand->stun_server->index;
+        break;
+      case PEER_REFLEXIVE:
+        if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_PEER_RFLX,&type_preference))
+          ABORT(r);
+        stun_priority=0;
+        break;
+      default:
+        ABORT(R_INTERNAL);
+    }
+
+    if(type_preference > 126)
+      r_log(LOG_ICE,LOG_ERR,"Illegal type preference %d",type_preference);
+
+      
+    if(r=NR_reg_get2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,
+      &interface_preference)) {
+      if (r==R_NOT_FOUND) {
+        if (next_automatic_preference == 1) {
+          r_log(LOG_ICE,LOG_DEBUG,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
+          ABORT(R_NOT_FOUND);
+        }
+        r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
+          next_automatic_preference);
+        if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
+          ABORT(r);
+        }
+        interface_preference=next_automatic_preference;
+        next_automatic_preference--;
+      }
+      else {
+        ABORT(r);
+      }
+    }
+
+    cand->priority=
+      (type_preference << 24) |
+      (interface_preference << 16) |
+      (stun_priority << 8) |
+      (256 - cand->component_id);
+
+    /* S 4.1.2 */    
+    assert(cand->priority>=1&&cand->priority<=2147483647);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg)
+  {
+    int r,_status;
+
+    cand->done_cb=ready_cb;
+    cand->cb_arg=cb_arg;
+
+    switch(cand->type){
+      case HOST:
+        if(r=nr_socket_getaddr(cand->isock->sock,&cand->addr))
+          ABORT(r);
+        cand->osock=cand->isock->sock;
+        cand->state=NR_ICE_CAND_STATE_INITIALIZED;
+        // Post this so that it doesn't happen in-line
+        NR_ASYNC_SCHEDULE(ready_cb,cb_arg);
+        break;
+#ifdef USE_TURN
+      case RELAYED:
+        if(r=nr_ice_start_relay_turn(cand,ready_cb,cb_arg))
+          ABORT(r);
+        ABORT(R_WOULDBLOCK);
+        break;
+#endif /* USE_TURN */
+      case SERVER_REFLEXIVE:
+        /* Need to start stun */
+        if(r=nr_ice_srvrflx_start_stun(cand,ready_cb,cb_arg))
+          ABORT(r);
+        cand->osock=cand->isock->sock;
+        ABORT(R_WOULDBLOCK);
+        break;
+      default:
+        ABORT(R_INTERNAL);
+    }
+
+    _status=0;
+  abort:
+    if(_status && _status!=R_WOULDBLOCK)
+      cand->state=NR_ICE_CAND_STATE_FAILED;
+    return(_status);
+  }
+
+static void nr_ice_srvrflx_start_stun_timer_cb(NR_SOCKET s, int how, void *cb_arg)
+  {
+    nr_ice_candidate *cand=cb_arg;
+    int r,_status;
+
+    cand->delay_timer=0;
+
+/* TODO: if the response is a BINDING-ERROR-RESPONSE, then restart
+ * TODO: using NR_STUN_CLIENT_MODE_BINDING_REQUEST because the
+ * TODO: server may not have understood the 0.96-style request */
+    if(r=nr_stun_client_start(cand->u.srvrflx.stun, NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96, nr_ice_srvrflx_stun_finished_cb, cand))
+      ABORT(r);
+
+    if(r=nr_ice_ctx_remember_id(cand->ctx, cand->u.srvrflx.stun->request))
+      ABORT(r);
+ 
+    if(r=nr_ice_socket_register_stun_client(cand->isock,cand->u.srvrflx.stun,&cand->u.srvrflx.stun_handle))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    if(_status){
+      cand->state=NR_ICE_CAND_STATE_FAILED;
+    }
+    
+    return;
+  }
+
+static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg)
+  {
+    int r,_status;
+ 
+    cand->done_cb=ready_cb;
+    cand->cb_arg=cb_arg;
+
+    cand->state=NR_ICE_CAND_STATE_INITIALIZING;
+
+    if(r=nr_stun_client_ctx_create(cand->label, cand->isock->sock,
+      &cand->stun_server->addr, cand->stream->ctx->gather_rto,
+      &cand->u.srvrflx.stun))
+      ABORT(r);
+
+    NR_ASYNC_TIMER_SET(cand->stream->ctx->stun_delay,nr_ice_srvrflx_start_stun_timer_cb,cand,&cand->delay_timer);
+    cand->stream->ctx->stun_delay += cand->stream->ctx->Ta; 
+
+    _status=0;
+  abort:
+    if(_status){
+      cand->state=NR_ICE_CAND_STATE_FAILED;
+    }
+    return(_status);
+  }
+
+#ifdef USE_TURN
+static void nr_ice_start_relay_turn_timer_cb(NR_SOCKET s, int how, void *cb_arg)
+  {
+    nr_ice_candidate *cand=cb_arg;
+    int r,_status;
+    int i;
+
+    cand->delay_timer=0;
+
+    if(r=nr_turn_client_allocate(cand->u.relayed.turn, cand->u.relayed.server->username, cand->u.relayed.server->password, cand->u.relayed.server->bandwidth_kbps, cand->u.relayed.server->lifetime_secs, nr_ice_turn_allocated_cb, cand))
+      ABORT(r);
+
+    assert((sizeof(cand->u.relayed.turn->stun_ctx)/sizeof(*cand->u.relayed.turn->stun_ctx))==3);
+    for(i=0;i<3;i++){
+      if(cand->u.relayed.turn->stun_ctx[i]&&cand->u.relayed.turn->stun_ctx[i]->request){
+        if(r=nr_ice_ctx_remember_id(cand->ctx, cand->u.relayed.turn->stun_ctx[i]->request))
+          ABORT(r);
+      }
+    }
+
+    if(r=nr_ice_socket_register_turn_client(cand->isock,cand->u.relayed.turn,&cand->u.relayed.turn_handle))
+      ABORT(r);
+
+
+    _status=0;
+  abort:
+    if(_status){
+      cand->state=NR_ICE_CAND_STATE_FAILED;
+    }
+    return;
+  }
+
+static int nr_ice_start_relay_turn(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg)
+  {
+    int r,_status;
+
+    if(r=nr_turn_client_ctx_create(cand->label, cand->isock->sock,
+      cand->osock,
+      &cand->stun_server->addr, cand->stream->ctx->gather_rto,
+      &cand->u.relayed.turn))
+      ABORT(r);
+
+    cand->done_cb=ready_cb;
+    cand->cb_arg=cb_arg;
+
+    NR_ASYNC_TIMER_SET(cand->stream->ctx->stun_delay,nr_ice_start_relay_turn_timer_cb,cand,&cand->delay_timer);
+    cand->stream->ctx->stun_delay += cand->stream->ctx->Ta;
+
+    _status=0;
+  abort:
+    if(_status){
+      cand->state=NR_ICE_CAND_STATE_FAILED;
+    }
+    return(_status);
+  }
+#endif /* USE_TURN */
+
+static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg)
+  {
+    int _status;
+    nr_ice_candidate *cand=cb_arg;
+
+    /* Deregister to suppress duplicates */
+    if(cand->u.srvrflx.stun_handle){ /* This test because we might have failed before CB registered */
+      nr_ice_socket_deregister(cand->isock,cand->u.srvrflx.stun_handle);
+      cand->u.srvrflx.stun_handle=0;
+    }
+
+    switch(cand->u.srvrflx.stun->state){
+      /* OK, we should have a mapped address */
+      case NR_STUN_CLIENT_STATE_DONE:
+        /* Copy the address */
+        nr_transport_addr_copy(&cand->addr, &cand->u.srvrflx.stun->results.stun_binding_response_stund_0_96.mapped_addr);
+        nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
+        cand->state=NR_ICE_CAND_STATE_INITIALIZED;
+        /* Execute the ready callback */
+        cand->done_cb(0,0,cand->cb_arg);
+        break;
+        
+      /* This failed, so go to the next STUN server if there is one */
+      case NR_STUN_CLIENT_STATE_FAILED:
+        ABORT(R_NOT_FOUND);
+        break;
+      default:
+        ABORT(R_INTERNAL);
+    }
+    _status = 0;
+  abort:
+    if(_status){
+      cand->state=NR_ICE_CAND_STATE_FAILED;
+      cand->done_cb(0,0,cand->cb_arg);
+    }
+  }
+
+#ifdef USE_TURN
+static void nr_ice_turn_allocated_cb(NR_SOCKET s, int how, void *cb_arg)
+  {
+    int r,_status;
+    nr_ice_candidate *cand=cb_arg;
+    nr_turn_client_ctx *turn=cand->u.relayed.turn;
+    int i;
+    char *label;
+
+    /* Deregister to suppress duplicates */
+    if(cand->u.relayed.turn_handle){ /* This test because we might have failed before CB registered */
+      nr_ice_socket_deregister(cand->isock,cand->u.relayed.turn_handle);
+      cand->u.relayed.turn_handle=0;
+    }
+
+    switch(turn->state){
+    /* OK, we should have a mapped address */
+    case NR_TURN_CLIENT_STATE_ALLOCATED:
+        /* switch candidate from TURN mode to STUN mode */
+
+        if(r=nr_concat_strings(&label,"turn-relay(",cand->base.as_string,"|",turn->relay_addr.as_string,")",NULL))
+          ABORT(r);
+
+        r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Switching from TURN (%s) to RELAY (%s)",cand->u.relayed.turn->label,cand->label,label);
+
+        /* Copy out mapped address and relay address */
+        nr_transport_addr_copy(&turn->relay_addr, &cand->u.relayed.turn->stun_ctx[NR_TURN_CLIENT_PHASE_ALLOCATE_REQUEST2]->results.allocate_response2.relay_addr);
+        nr_transport_addr_copy(&cand->addr, &turn->relay_addr);
+
+        r_log(LOG_ICE,LOG_DEBUG,"ICE-CANDIDATE(%s): base=%s, candidate=%s", cand->label, cand->base.as_string, cand->addr.as_string);
+
+        RFREE(cand->label);
+        cand->label=label;
+        cand->state=NR_ICE_CAND_STATE_INITIALIZED;
+
+        nr_socket_turn_set_state(cand->osock, NR_TURN_CLIENT_STATE_ALLOCATED);
+        nr_socket_turn_set_relay_addr(cand->osock, &turn->relay_addr);
+
+        /* Execute the ready callback */
+        cand->done_cb(0,0,cand->cb_arg);
+
+        
+        /* We also need to activate the associated STUN candidate */
+        if(cand->u.relayed.srvflx_candidate){
+          nr_ice_candidate *cand2=cand->u.relayed.srvflx_candidate;
+
+          nr_transport_addr_copy(&cand2->addr, &cand->u.relayed.turn->stun_ctx[NR_TURN_CLIENT_PHASE_ALLOCATE_REQUEST2]->results.allocate_response2.mapped_addr);
+          cand2->state=NR_ICE_CAND_STATE_INITIALIZED;
+          cand2->done_cb(0,0,cand2->cb_arg);
+        }
+        
+        break;
+        
+    case NR_TURN_CLIENT_STATE_FAILED:
+    case NR_TURN_CLIENT_STATE_TIMED_OUT:
+    case NR_TURN_CLIENT_STATE_CANCELLED:
+      /* This failed, so go to the next TURN server if there is one */
+      ABORT(R_NOT_FOUND);
+      break;
+    default:
+      assert(0); /* should never happen */
+      ABORT(R_INTERNAL);
+    }
+
+    for(i=0;i<3;i++){
+      if(cand->u.relayed.turn->stun_ctx[i]&&cand->u.relayed.turn->stun_ctx[i]->request&&!cand->u.relayed.turn->stun_ctx[i]->response){
+        if(r=nr_ice_ctx_remember_id(cand->ctx, cand->u.relayed.turn->stun_ctx[i]->request))
+          ABORT(r);
+      }
+    }
+
+    _status=0;
+  abort:
+    if(_status){
+      cand->state=NR_ICE_CAND_STATE_FAILED;
+      cand->done_cb(0,0,cand->cb_arg);
+
+      if(cand->u.relayed.srvflx_candidate){
+        nr_ice_candidate *cand2=cand->u.relayed.srvflx_candidate;
+        
+        cand2->state=NR_ICE_CAND_STATE_FAILED;
+        cand2->done_cb(0,0,cand2->cb_arg);
+      }
+    }
+    /*return(_status);*/
+  }
+#endif /* USE_TURN */
+
+/* Format the candidate attribute as per ICE S 15.1 */
+int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int maxlen)
+  {
+    int r,_status;
+    char addr[64];
+    int port;
+    int len;
+
+    assert(!strcmp(nr_ice_candidate_type_names[HOST], "host"));
+    assert(!strcmp(nr_ice_candidate_type_names[RELAYED], "relay"));
+
+    if(r=nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr)))
+      ABORT(r);
+    if(r=nr_transport_addr_get_port(&cand->addr,&port))
+      ABORT(r);
+    snprintf(attr,maxlen,"candidate:%s %d UDP %u %s %d typ %s",
+      cand->foundation, cand->component_id, cand->priority, addr, port,
+      nr_ice_candidate_type_names[cand->type]);
+
+    len=strlen(attr); attr+=len; maxlen-=len;
+
+    /* raddr, rport */
+    switch(cand->type){
+      case HOST:
+        break;
+      case SERVER_REFLEXIVE:
+      case PEER_REFLEXIVE:
+        if(r=nr_transport_addr_get_addrstring(&cand->base,addr,sizeof(addr)))
+          ABORT(r);
+        if(r=nr_transport_addr_get_port(&cand->base,&port))
+          ABORT(r);
+        
+        snprintf(attr,maxlen," raddr %s rport %d",addr,port);
+        break;
+      case RELAYED:
+        // comes from XorMappedAddress via AllocateResponse
+        if(r=nr_transport_addr_get_addrstring(&cand->base,addr,sizeof(addr)))
+          ABORT(r);
+        if(r=nr_transport_addr_get_port(&cand->base,&port))
+          ABORT(r);
+
+        snprintf(attr,maxlen," raddr %s rport %d",addr,port);
+        break;
+      default:
+        UNIMPLEMENTED;
+        break;
+    }
+    _status=0;
+  abort:
+    return(_status);
+  }
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.h
@@ -0,0 +1,110 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _ice_candidate_h
+#define _ice_candidate_h
+#ifdef __cplusplus
+using namespace std;
+extern "C" {
+#endif /* __cplusplus */
+
+typedef enum {HOST=1, SERVER_REFLEXIVE, PEER_REFLEXIVE, RELAYED} nr_ice_candidate_type;
+
+struct nr_ice_candidate_ {
+  char *label;
+  int state;
+#define NR_ICE_CAND_STATE_CREATED          1
+#define NR_ICE_CAND_STATE_INITIALIZING     2
+#define NR_ICE_CAND_STATE_INITIALIZED      3
+#define NR_ICE_CAND_STATE_FAILED           4
+#define NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED 9
+#define NR_ICE_CAND_PEER_CANDIDATE_PAIRED   10
+  struct nr_ice_ctx_ *ctx;
+  nr_ice_socket *isock;               /* The socket to read from
+                                         (it contains all other candidates
+                                         on this socket) */
+  nr_socket *osock;                   /* The socket to write to */
+  nr_ice_media_stream *stream;        /* The media stream this is associated with */
+  nr_ice_component *component;        /* The component this is associated with */
+  nr_ice_candidate_type type;         /* The type of the candidate (S 4.1.1) */
+  UCHAR component_id;                 /* The component id (S 4.1.2.1) */
+  nr_transport_addr addr;             /* The advertised address;
+                                         JDR calls this the candidate */
+  nr_transport_addr base;             /* The base address (S 2.1)*/
+  char *foundation;                   /* Foundation for the candidate (S 4) */
+  UINT4 priority;                     /* The priority value (S 5.4 */
+  nr_ice_stun_server *stun_server;
+  
+  void *delay_timer;
+
+  /* Holding data for STUN and TURN */
+  union {
+    struct {
+      nr_stun_client_ctx *stun;      
+      void *stun_handle;
+    } srvrflx;
+    struct {
+      nr_turn_client_ctx *turn;
+      nr_ice_turn_server *server;
+      nr_ice_candidate *srvflx_candidate;
+      nr_socket *turn_sock;
+      void *turn_handle;
+    } relayed;
+  } u;
+
+  NR_async_cb done_cb;              
+  void *cb_arg;
+
+  TAILQ_ENTRY(nr_ice_candidate_) entry_sock;  
+  TAILQ_ENTRY(nr_ice_candidate_) entry_comp;
+};
+
+extern char *nr_ice_candidate_type_names[];
+
+
+int nr_ice_candidate_create(struct nr_ice_ctx_ *ctx,char *label, nr_ice_component *component, nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp);
+int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg);
+int nr_ice_candidate_process_stun(nr_ice_candidate *cand, UCHAR *msg, int len, nr_transport_addr *faddr);
+int nr_ice_candidate_destroy(nr_ice_candidate **candp);
+void nr_ice_candidate_destroy_cb(NR_SOCKET s, int h, void *cb_arg);
+int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int maxlen);
+int nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *attr,nr_ice_media_stream *stream,nr_ice_candidate **candp);
+int nr_ice_peer_peer_rflx_candidate_create(nr_ice_ctx *ctx,char *label, nr_ice_component *comp,nr_transport_addr *addr, nr_ice_candidate **candp);
+int nr_ice_candidate_compute_priority(nr_ice_candidate *cand);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.c
@@ -0,0 +1,591 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: ice_candidate_pair.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
+
+#include <assert.h>
+#include <string.h>
+#include <nr_api.h>
+#include "ice_ctx.h"
+#include "ice_util.h"
+#include "ice_codeword.h"
+#include "stun.h"
+
+static char *nr_ice_cand_pair_states[]={"UNKNOWN","FROZEN","WAITING","IN_PROGRESS","FAILED","SUCCEEDED","CANCELLED"};
+
+static void nr_ice_candidate_pair_restart_stun_controlled_cb(NR_SOCKET s, int how, void *cb_arg);
+static void nr_ice_candidate_pair_compute_codeword(nr_ice_cand_pair *pair,
+  nr_ice_candidate *lcand, nr_ice_candidate *rcand);
+
+int nr_ice_candidate_pair_create(nr_ice_peer_ctx *pctx, nr_ice_candidate *lcand,nr_ice_candidate *rcand,nr_ice_cand_pair **pairp)
+  {
+    nr_ice_cand_pair *pair=0;
+    UINT8 o_priority, a_priority;
+    char *lufrag,*rufrag;
+    char *lpwd,*rpwd;
+    char *l2ruser=0,*r2lpass=0;
+    int r,_status;
+    UINT4 RTO;
+    nr_ice_candidate tmpcand;
+    UINT8 t_priority;
+
+    if(!(pair=RCALLOC(sizeof(nr_ice_cand_pair))))
+      ABORT(R_NO_MEMORY);
+    
+    pair->pctx=pctx;
+    
+    nr_ice_candidate_pair_compute_codeword(pair,lcand,rcand);
+    
+    if(r=nr_concat_strings(&pair->as_string,pair->codeword,"|",lcand->addr.as_string,"|",
+        rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")", NULL))
+      ABORT(r);
+
+    nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_FROZEN);
+    pair->local=lcand;
+    pair->remote=rcand;
+
+    /* Priority computation S 5.7.2 */
+    if(pctx->ctx->flags & NR_ICE_CTX_FLAGS_OFFERER)
+    {
+      assert(!(pctx->ctx->flags & NR_ICE_CTX_FLAGS_ANSWERER));
+      
+      o_priority=lcand->priority;
+      a_priority=rcand->priority;
+    }
+    else{
+      o_priority=rcand->priority;
+      a_priority=lcand->priority;
+    }
+    pair->priority=(MIN(o_priority, a_priority))<<32 | 
+      (MAX(o_priority, a_priority))<<1 | (o_priority > a_priority?0:1);
+    
+    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Pairing candidate %s (%x):%s (%x) priority=%llu (%llx) codeword=%s",pctx->ctx->label,lcand->addr.as_string,lcand->priority,rcand->addr.as_string,rcand->priority,pair->priority,pair->priority,pair->codeword);
+
+    /* Foundation */
+    if(r=nr_concat_strings(&pair->foundation,lcand->foundation,"|",
+      rcand->foundation,NULL))
+      ABORT(r);
+
+
+    /* OK, now the STUN data */
+    lufrag=lcand->stream->ufrag?lcand->stream->ufrag:pctx->ctx->ufrag;
+    lpwd=lcand->stream->pwd?lcand->stream->pwd:pctx->ctx->pwd;
+    rufrag=rcand->stream->ufrag?rcand->stream->ufrag:pctx->peer_ufrag;
+    rpwd=rcand->stream->pwd?rcand->stream->pwd:pctx->peer_pwd;
+
+
+    /* Compute the RTO per S 16 */
+    RTO = MAX(100, (pctx->ctx->Ta * pctx->waiting_pairs));
+
+    /* Make a bogus candidate to compute a theoretical peer reflexive
+     * priority per S 7.1.1.1 */
+    memcpy(&tmpcand, lcand, sizeof(tmpcand));
+    tmpcand.type = PEER_REFLEXIVE;
+    if (r=nr_ice_candidate_compute_priority(&tmpcand))
+      ABORT(r);
+    t_priority = tmpcand.priority;
+
+    /* Our sending context */
+    if(r=nr_concat_strings(&l2ruser,lufrag,":",rufrag,NULL))
+      ABORT(r);
+    if(r=nr_stun_client_ctx_create(pair->as_string,
+      lcand->osock,
+      &rcand->addr,RTO,&pair->stun_client))
+      ABORT(r);
+    if(!(pair->stun_client->params.ice_binding_request.username=r_strdup(l2ruser)))
+      ABORT(R_NO_MEMORY);
+    if(r=r_data_make(&pair->stun_client->params.ice_binding_request.password,(UCHAR *)lpwd,strlen(lpwd)))
+      ABORT(r);
+    pair->stun_client->params.ice_binding_request.priority=t_priority;
+    pair->stun_client->params.ice_binding_request.control = pctx->controlling?
+      NR_ICE_CONTROLLING:NR_ICE_CONTROLLED;
+
+    pair->stun_client->params.ice_binding_request.tiebreaker=pctx->tiebreaker;
+
+    /* Our receiving username/passwords. Stash these for later 
+       injection into the stun server ctx*/
+    if(r=nr_concat_strings(&pair->r2l_user,rufrag,":",lufrag,NULL))
+      ABORT(r);
+    if(!(r2lpass=r_strdup(rpwd)))
+      ABORT(R_NO_MEMORY);
+    INIT_DATA(pair->r2l_pwd,(UCHAR *)r2lpass,strlen(r2lpass));
+    
+    *pairp=pair;
+
+    _status=0;
+  abort:
+    RFREE(l2ruser);
+    if(_status){
+      RFREE(r2lpass);
+    }
+    return(_status);
+  }
+
+int nr_ice_candidate_pair_destroy(nr_ice_cand_pair **pairp)
+  {
+    nr_ice_cand_pair *pair;
+
+    if(!pairp || !*pairp)
+      return(0);
+
+    pair=*pairp;
+    *pairp=0;
+
+    RFREE(pair->as_string);
+    RFREE(pair->foundation);
+    nr_ice_socket_deregister(pair->local->isock,pair->stun_client_handle);
+    RFREE(pair->stun_client->params.ice_binding_request.username);
+    RFREE(pair->stun_client->params.ice_binding_request.password.data);
+    nr_stun_client_ctx_destroy(&pair->stun_client);
+    
+    RFREE(pair->r2l_user);
+    RFREE(pair->r2l_pwd.data);
+
+    RFREE(pair);
+    return(0);
+  }
+
+int nr_ice_candidate_pair_unfreeze(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair)
+  {
+    assert(pair->state==NR_ICE_PAIR_STATE_FROZEN);
+    
+    nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_WAITING);
+    
+    return(0);
+  }
+
+static void nr_ice_candidate_pair_stun_cb(NR_SOCKET s, int how, void *cb_arg)
+  {
+    int r,_status;
+    nr_ice_cand_pair *pair=cb_arg,*orig_pair;
+    nr_ice_candidate *cand=0;
+    nr_stun_message *sres;
+    nr_transport_addr *request_src;
+    nr_transport_addr *request_dst;
+    nr_transport_addr *response_src;
+    nr_transport_addr response_dst;
+    nr_stun_message_attribute *attr;
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s): STUN cb on pair %s",
+      pair->pctx->label,pair->local->stream->label,pair->as_string);
+
+    /* This ordinarily shouldn't happen, but can if we're
+       doing the second check to confirm nomination. 
+       Just bail out */
+    if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED)
+      goto done;
+
+    switch(pair->stun_client->state){
+      case NR_STUN_CLIENT_STATE_FAILED:
+        sres=pair->stun_client->response;
+        if(sres && nr_stun_message_has_attribute(sres,NR_STUN_ATTR_ERROR_CODE,&attr)&&attr->u.error_code.number==487){
+          r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): detected role conflict. Switching to controlled",pair->pctx->label);
+          
+          pair->pctx->controlling=0;
+          
+          NR_ASYNC_SCHEDULE(nr_ice_candidate_pair_restart_stun_controlled_cb,pair);
+          
+          return;
+        }
+        /* Fall through */
+      case NR_STUN_CLIENT_STATE_TIMED_OUT:
+        nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
+        break;
+      case NR_STUN_CLIENT_STATE_DONE:
+        /* make sure the addresses match up S 7.1.2.2 */
+        response_src=&pair->stun_client->peer_addr;
+        request_dst=&pair->remote->addr;
+        if (nr_transport_addr_cmp(response_src,request_dst,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
+          r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): Peer address mismatch %s/%s",pair->pctx->label, response_src->as_string,request_dst->as_string);
+          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
+          break;
+        }
+        request_src=&pair->stun_client->my_addr;
+        nr_socket_getaddr(pair->local->isock->sock,&response_dst);
+        if (nr_transport_addr_cmp(request_src,&response_dst,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
+          r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): Address mismatch %s/%s",pair->pctx->label, request_src->as_string,response_dst.as_string);
+          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
+          break;
+        }
+ 
+        if(strlen(pair->stun_client->results.ice_binding_response.mapped_addr.as_string)==0){
+          /* we're using the mapped_addr returned by the server to lookup our
+           * candidate, but if the server fails to do that we can't perform
+           * the lookup -- this may be a BUG because if we've gotten here 
+           * then the transaction ID check succeeded, and perhaps we should
+           * just assume that it's the server we're talking to and that our
+           * peer is ok, but I'm not sure how that'll interact with the 
+           * peer reflexive logic below */
+          r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): server failed to return mapped address on pair %s", pair->pctx->label,pair->as_string);
+          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FAILED);
+          break;
+        }
+        else if(!nr_transport_addr_cmp(&pair->local->addr,&pair->stun_client->results.ice_binding_response.mapped_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
+          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_SUCCEEDED);
+        }
+        else{
+          /* OK, this didn't correspond to a pair on the check list, but
+             it probably matches one of our candidates */
+
+          cand=TAILQ_FIRST(&pair->local->component->candidates);
+          while(cand){
+            if(!nr_transport_addr_cmp(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
+              break;
+ 
+            cand=TAILQ_NEXT(cand,entry_comp);
+          }
+ 
+          /* OK, nothing found, must be peer reflexive */
+          if(!cand){
+            if(r=nr_ice_candidate_create(pair->pctx->ctx,"prflx",
+              pair->local->component,pair->local->isock,pair->local->osock,
+              PEER_REFLEXIVE,0,pair->local->component->component_id,&cand))
+              ABORT(r);
+            if(r=nr_transport_addr_copy(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr))
+              ABORT(r);
+            cand->state=NR_ICE_CAND_STATE_INITIALIZED;
+            TAILQ_INSERT_TAIL(&pair->local->component->candidates,cand,entry_comp);
+          }
+
+          /* Note: we stomp the existing pair! */
+          orig_pair=pair;
+          if(r=nr_ice_candidate_pair_create(pair->pctx,cand,pair->remote,
+            &pair))
+            ABORT(r);
+
+          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_SUCCEEDED);
+
+          if(r=nr_ice_candidate_pair_insert(&pair->remote->stream->check_list,pair))
+            ABORT(r);
+          
+          /* If the original pair was nominated, make us nominated,
+             since we replace him*/
+          if(orig_pair->peer_nominated)
+            pair->peer_nominated=1;
+
+          
+          /* Now mark the orig pair failed */
+          nr_ice_candidate_pair_set_state(orig_pair->pctx,orig_pair,NR_ICE_PAIR_STATE_FAILED); 
+          
+        }
+        
+        /* Should we set nominated? */
+        if(pair->pctx->controlling){
+          if(pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION)
+            pair->nominated=1;
+        }
+        else{
+          if(pair->peer_nominated)
+            pair->nominated=1;
+        }
+        
+        
+        /* increment the number of valid pairs in the component */
+        /* We don't bother to maintain a separate valid list */
+        pair->remote->component->valid_pairs++;
+        
+        /* S 7.1.2.2: unfreeze other pairs with the same foundation*/
+        if(r=nr_ice_media_stream_unfreeze_pairs_foundation(pair->remote->stream,pair->foundation))
+          ABORT(r);
+        
+        /* Deal with this pair being nominated */
+        if(pair->nominated){
+          if(r=nr_ice_component_nominated_pair(pair->remote->component, pair))
+            ABORT(r);
+        }
+
+        break;
+      default:
+        ABORT(R_INTERNAL);
+    }
+    
+    /* If we're controlling but in regular mode, ask the handler
+       if he wants to nominate something and stop... */
+    if(pair->pctx->controlling && !(pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION)){
+      
+      if(r=nr_ice_component_select_pair(pair->pctx,pair->remote->component)){
+        if(r!=R_NOT_FOUND)
+          ABORT(r);
+      }
+    }
+
+  done:
+    _status=0;
+  abort:
+    return;
+  }
+
+int nr_ice_candidate_pair_start(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair)
+  {
+    int r,_status;
+    UINT4 mode;
+
+    nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_IN_PROGRESS);
+
+    /* Register the stun ctx for when responses come in*/
+    if(r=nr_ice_socket_register_stun_client(pair->local->isock,pair->stun_client,&pair->stun_client_handle))
+      ABORT(r);
+    
+    /* Start STUN */
+    if(pair->pctx->controlling && (pair->pctx->ctx->flags & NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION))
+      mode=NR_ICE_CLIENT_MODE_USE_CANDIDATE;
+    else
+      mode=NR_ICE_CLIENT_MODE_BINDING_REQUEST;
+
+    if(r=nr_stun_client_start(pair->stun_client,mode,nr_ice_candidate_pair_stun_cb,pair))
+      ABORT(r);
+
+    if ((r=nr_ice_ctx_remember_id(pair->pctx->ctx, pair->stun_client->request))) {
+      /* ignore if this fails (which it shouldn't) because it's only an
+       * optimization and the cleanup routines are not going to do the right
+       * thing if this fails */
+      assert(0);
+    }
+
+    _status=0;
+  abort:
+    if(_status){
+      /* Don't fire the CB, but schedule it to fire */
+      NR_ASYNC_SCHEDULE(nr_ice_candidate_pair_stun_cb,pair);
+      _status=0;
+    }
+    return(_status);
+  }
+
+
+int nr_ice_candidate_pair_do_triggered_check(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair)
+  {
+    int r,_status;
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): triggered check on %s",pctx,pair->as_string);
+
+    switch(pair->state){
+      case NR_ICE_PAIR_STATE_FROZEN:
+        nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_WAITING);
+        /* Fall through */
+      case NR_ICE_PAIR_STATE_WAITING:
+        /* Start the checks */
+        if(r=nr_ice_candidate_pair_start(pctx,pair))
+          ABORT(r);
+        break;
+      case NR_ICE_PAIR_STATE_IN_PROGRESS:
+        if(r=nr_stun_client_force_retransmit(pair->stun_client))
+          ABORT(r);
+        break;
+      default:
+        break;
+    }
+    
+    /* Activate the media stream if required */
+    if(pair->remote->stream->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FROZEN){
+      if(r=nr_ice_media_stream_start_checks(pair->pctx,pair->remote->stream))
+        ABORT(r);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_candidate_pair_cancel(nr_ice_peer_ctx *pctx,nr_ice_cand_pair *pair)
+  {
+    if(pair->state != NR_ICE_PAIR_STATE_FAILED){
+      /* If it's already running we need to terminate the stun */
+      if(pair->state==NR_ICE_PAIR_STATE_IN_PROGRESS){
+        nr_stun_client_cancel(pair->stun_client);
+      }
+      nr_ice_candidate_pair_set_state(pctx,pair,NR_ICE_PAIR_STATE_CANCELLED);
+    }
+
+    return(0);
+  }
+
+int nr_ice_candidate_pair_select(nr_ice_cand_pair *pair)
+  {
+    int r,_status;
+   
+    if(!pair){
+      r_log(LOG_ICE,LOG_ERR,"ICE-PAIR: No pair chosen");
+      ABORT(R_BAD_ARGS);
+    }
+
+    if(pair->state!=NR_ICE_PAIR_STATE_SUCCEEDED){
+      r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): tried to install non-succeeded pair %s, ignoring",pair->pctx->label,pair->as_string);
+    }
+    else{
+      /* Ok, they chose one */
+      /* 1. Send a new request with nominated. Do it as a scheduled
+            event to avoid reentrancy issues  */
+      NR_ASYNC_SCHEDULE(nr_ice_candidate_pair_restart_stun_nominated_cb,pair);
+      /* 2. Tell ourselves this pair is ready */
+      if(r=nr_ice_component_nominated_pair(pair->remote->component, pair))
+        ABORT(r);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+ }
+
+int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state)
+  {
+    int r,_status;
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): setting pair %s to %s",
+      pctx->label,pair->as_string,nr_ice_cand_pair_states[state]);
+
+    /* NOTE: This function used to reference pctx->state instead of
+       pair->state and the assignment to pair->state was at the top
+       of this function. Because pctx->state was never changed, this seems to have
+       been a typo. The natural logic is "if the state changed
+       decrement the counter" so this implies we should be checking
+       the pair state rather than the pctx->state.
+
+       This didn't cause big problems because waiting_pairs was only
+       used for pacing, so the pacing just was kind of broken.
+       
+       This note is here as a reminder until we do more testing
+       and make sure that in fact this was a typo.
+    */
+    if(pair->state!=NR_ICE_PAIR_STATE_WAITING){
+      if(state==NR_ICE_PAIR_STATE_WAITING)
+        pctx->waiting_pairs++;
+    }
+    else{
+      if(state!=NR_ICE_PAIR_STATE_WAITING)
+        pctx->waiting_pairs--;
+
+      assert(pctx->waiting_pairs>=0);
+    }
+    pair->state=state;
+
+
+    if(pair->state==NR_ICE_PAIR_STATE_FAILED){
+      if(r=nr_ice_component_failed_pair(pair->remote->component, pair))
+        ABORT(r);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_candidate_pair_dump_state(nr_ice_cand_pair *pair, FILE *out)
+  {
+    //r_log(LOG_ICE,LOG_DEBUG,"pair %s: state=%s, priority=0x%llx\n",pair->as_string,nr_ice_cand_pair_states[pair->state],pair->priority);
+    
+    return(0);
+  }
+
+
+int nr_ice_candidate_pair_insert(nr_ice_cand_pair_head *head,nr_ice_cand_pair *pair)
+  {
+    nr_ice_cand_pair *c1;
+
+    c1=TAILQ_FIRST(head);
+    while(c1){
+      if(c1->priority < pair->priority){
+        TAILQ_INSERT_BEFORE(c1,pair,entry);
+        break;
+      }
+        
+      c1=TAILQ_NEXT(c1,entry);
+    }
+    if(!c1) TAILQ_INSERT_TAIL(head,pair,entry);
+
+    return(0);
+  }
+
+void nr_ice_candidate_pair_restart_stun_nominated_cb(NR_SOCKET s, int how, void *cb_arg)
+  {
+    nr_ice_cand_pair *pair=cb_arg;
+    int r,_status;
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s):%d: Restarting pair %s as nominated",pair->pctx->label,pair->local->stream->label,pair->remote->component->component_id,pair->as_string);
+
+    nr_stun_client_reset(pair->stun_client);
+    pair->stun_client->params.ice_binding_request.control=NR_ICE_CONTROLLING;
+
+    if(r=nr_stun_client_start(pair->stun_client,NR_ICE_CLIENT_MODE_USE_CANDIDATE,nr_ice_candidate_pair_stun_cb,pair))
+      ABORT(r);
+
+    if(r=nr_ice_ctx_remember_id(pair->pctx->ctx, pair->stun_client->request))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return;
+  }
+
+static void nr_ice_candidate_pair_restart_stun_controlled_cb(NR_SOCKET s, int how, void *cb_arg)
+  {
+    nr_ice_cand_pair *pair=cb_arg;
+    int r,_status;
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s):%d: Restarting pair %s as CONTROLLED",pair->pctx->label,pair->local->stream->label,pair->remote->component->component_id,pair->as_string);
+
+    nr_stun_client_reset(pair->stun_client);
+    pair->stun_client->params.ice_binding_request.control=NR_ICE_CONTROLLED;
+
+    if(r=nr_stun_client_start(pair->stun_client,NR_ICE_CLIENT_MODE_BINDING_REQUEST,nr_ice_candidate_pair_stun_cb,pair))
+      ABORT(r);
+
+    if(r=nr_ice_ctx_remember_id(pair->pctx->ctx, pair->stun_client->request))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return;
+  }
+
+
+
+static void nr_ice_candidate_pair_compute_codeword(nr_ice_cand_pair *pair,
+  nr_ice_candidate *lcand, nr_ice_candidate *rcand)
+  {
+    int r,_status;
+    char *as_string=0;
+
+    if(r=nr_concat_strings(&as_string,lcand->addr.as_string,"|",
+      rcand->addr.as_string,"(",lcand->label,"|",rcand->label,")",NULL))
+      ABORT(r);
+
+    nr_ice_compute_codeword(as_string,strlen(as_string),pair->codeword);
+
+    _status=0;
+      abort:
+    RFREE(as_string);
+return;
+  }
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate_pair.h
@@ -0,0 +1,89 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _ice_candidate_pair_h
+#define _ice_candidate_pair_h
+#ifdef __cplusplus
+using namespace std;
+extern "C" {
+#endif /* __cplusplus */
+
+
+struct nr_ice_cand_pair_ {
+  nr_ice_peer_ctx *pctx;
+  char codeword[5];
+  char *as_string;
+  int state;                          /* The current state (S 5.7.3) */
+#define NR_ICE_PAIR_STATE_FROZEN           1
+#define NR_ICE_PAIR_STATE_WAITING          2
+#define NR_ICE_PAIR_STATE_IN_PROGRESS      3
+#define NR_ICE_PAIR_STATE_FAILED           4
+#define NR_ICE_PAIR_STATE_SUCCEEDED        5
+#define NR_ICE_PAIR_STATE_CANCELLED        6
+
+  UCHAR peer_nominated;               /* The peer sent USE-CANDIDATE 
+                                         on this check */
+  UCHAR nominated;                    /* Is this nominated or not */
+
+  UINT8 priority;                  /* The priority for this pair */
+  nr_ice_candidate *local;            /* The local candidate */
+  nr_ice_candidate *remote;           /* The remote candidate */
+  char *foundation;                   /* The combined foundations */
+       
+  char *r2l_user;                     /* Stashed username */
+  Data r2l_pwd;                       /* Stashed password */
+
+  nr_stun_client_ctx *stun_client;    /* STUN context when acting as a client */
+  void *stun_client_handle;
+  
+  TAILQ_ENTRY(nr_ice_cand_pair_) entry;
+};
+
+int nr_ice_candidate_pair_create(nr_ice_peer_ctx *pctx, nr_ice_candidate *lcand,nr_ice_candidate *rcand,nr_ice_cand_pair **pairp);
+int nr_ice_candidate_pair_unfreeze(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair);
+int nr_ice_candidate_pair_start(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair);
+int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair, int state);
+int nr_ice_candidate_pair_dump_state(nr_ice_cand_pair *pair, FILE *out);
+int nr_ice_candidate_pair_cancel(nr_ice_peer_ctx *pctx,nr_ice_cand_pair *pair);
+int nr_ice_candidate_pair_select(nr_ice_cand_pair *pair);
+int nr_ice_candidate_pair_do_triggered_check(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pair);
+int nr_ice_candidate_pair_insert(nr_ice_cand_pair_head *head,nr_ice_cand_pair *pair);
+void nr_ice_candidate_pair_restart_stun_nominated_cb(NR_SOCKET s, int how, void *cb_arg);
+int nr_ice_candidate_pair_destroy(nr_ice_cand_pair **pairp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_codeword.h
@@ -0,0 +1,41 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _ice_codeword_h
+#define _ice_codeword_h
+
+void nr_ice_compute_codeword(char *buf, int len,char *codeword);
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c
@@ -0,0 +1,812 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: ice_component.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
+
+#include <string.h>
+#include <assert.h>
+#include <nr_api.h>
+#include <registry.h>
+#include <async_timer.h>
+#include "ice_ctx.h"
+#include "ice_codeword.h"
+#include "stun.h"
+#include "nr_socket_local.h"
+#include "nr_socket_turn.h"
+#include "ice_reg.h"
+
+int nr_ice_component_create(nr_ice_media_stream *stream, int component_id, nr_ice_component **componentp)
+  {
+    int _status;
+    nr_ice_component *comp=0;
+
+    if(!(comp=RCALLOC(sizeof(nr_ice_component))))
+      ABORT(R_NO_MEMORY);
+
+    comp->state=NR_ICE_COMPONENT_RUNNING;
+    comp->component_id=component_id;
+    comp->stream=stream;
+    comp->ctx=stream->ctx;
+
+    STAILQ_INIT(&comp->sockets);
+    TAILQ_INIT(&comp->candidates);
+    STAILQ_INSERT_TAIL(&stream->components,comp,entry);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_component_destroy(nr_ice_component **componentp)
+  {
+    nr_ice_component *component;
+    nr_ice_socket *s1,*s2;
+    nr_ice_candidate *c1,*c2;
+
+    if(!componentp || !*componentp)
+      return(0);
+    
+    component=*componentp;
+    *componentp=0;
+
+    STAILQ_FOREACH_SAFE(s1, &component->sockets, entry, s2){
+      STAILQ_REMOVE(&component->sockets,s1,nr_ice_socket_,entry);
+      nr_ice_socket_destroy(&s1);
+    }
+    
+    
+    TAILQ_FOREACH_SAFE(c1, &component->candidates, entry_comp, c2){
+      TAILQ_REMOVE(&component->candidates,c1,entry_comp);
+      nr_ice_candidate_destroy(&c1);
+    }
+    
+    if(component->keepalive_timer)
+      NR_async_timer_cancel(component->keepalive_timer);
+    nr_stun_client_ctx_destroy(&component->keepalive_ctx);
+    
+    RFREE(component);
+    return(0);
+  }
+
+#define MAXADDRS 100 // Ridiculously high
+/* Make all the candidates we can make at the beginning */
+int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *component)
+  {
+    int r,_status;
+    nr_transport_addr addrs[MAXADDRS];
+    nr_socket *sock;
+    nr_ice_socket *isock=0;
+    nr_ice_candidate *cand=0;
+    int addr_ct;
+    int i;
+    int j;
+    char label[256];
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): initializing component with id %d",ctx->label,component->component_id);
+
+    /* First, gather all the local addresses we have */
+    if(r=nr_stun_find_local_addresses(addrs,MAXADDRS,&addr_ct)) {
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to find local addresses",ctx->label);      
+      ABORT(r);
+    }
+
+    if(addr_ct==0){
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): no local addresses available",ctx->label);      
+      ABORT(R_NOT_FOUND);
+    }
+
+    /* Now one ice_socket for each address */
+    for(i=0;i<addr_ct;i++){
+      char suppress;
+
+      if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].ifname,&suppress)){
+        if(r!=R_NOT_FOUND)
+          ABORT(r);
+      }
+      else{
+        if(suppress)
+          continue;
+      }
+
+      
+      r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): host address %s",ctx->label,addrs[i].as_string);
+      if(r=nr_socket_local_create(&addrs[i],&sock)){
+        r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create socket for address %s",ctx->label,addrs[i].as_string);
+        continue;
+      }
+
+      if(r=nr_ice_socket_create(ctx,component,sock,&isock))
+        ABORT(r);
+      
+      /* Create one host candidate */
+
+      snprintf(label, sizeof(label), "host(%s)", addrs[i].as_string);
+      if(r=nr_ice_candidate_create(ctx,label,component,isock,sock,HOST,0,
+        component->component_id,&cand))
+        ABORT(r);
+
+      TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
+      component->candidate_ct++;
+      cand=0;
+
+      /* And a srvrflx candidate for each STUN server */
+      for(j=0;j<ctx->stun_server_ct;j++){
+        snprintf(label, sizeof(label), "srvrflx(%s|%s)", addrs[i].as_string, ctx->stun_servers[j].addr.as_string);
+        if(r=nr_ice_candidate_create(ctx,label,component,
+          isock,sock,SERVER_REFLEXIVE,
+          &ctx->stun_servers[j],component->component_id,&cand))
+          ABORT(r);
+        TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
+        component->candidate_ct++;
+        cand=0;
+      }
+
+#ifdef USE_TURN
+      /* And both a srvrflx and relayed candidate for each TURN server */
+      for(j=0;j<ctx->turn_server_ct;j++){
+        nr_socket *turn_sock;
+        nr_ice_candidate *srvflx_cand;
+
+        /* srvrflx */
+        snprintf(label, sizeof(label), "srvrflx(%s|%s)", addrs[i].as_string, ctx->turn_servers[j].turn_server.addr.as_string);
+        if(r=nr_ice_candidate_create(ctx,label,component,
+          isock,sock,SERVER_REFLEXIVE,
+          &ctx->turn_servers[j].turn_server,component->component_id,&cand))
+          ABORT(r);
+        cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
+        cand->done_cb=nr_ice_initialize_finished_cb;
+        cand->cb_arg=ctx;
+
+        TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
+        component->candidate_ct++;
+        srvflx_cand=cand;
+
+        /* relayed*/
+        if(r=nr_socket_turn_create(sock, 0, &turn_sock))
+          ABORT(r);
+        snprintf(label, sizeof(label), "turn-relayed(%s|%s)", addrs[i].as_string, ctx->turn_servers[j].turn_server.addr.as_string);
+        if(r=nr_ice_candidate_create(ctx,label,component,
+          isock,turn_sock,RELAYED,
+          &ctx->turn_servers[j].turn_server,component->component_id,&cand))
+           ABORT(r);
+        cand->u.relayed.srvflx_candidate=srvflx_cand;
+        cand->u.relayed.server=&ctx->turn_servers[j];
+        TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
+        component->candidate_ct++;
+
+        cand=0;
+      }
+#endif /* USE_TURN */
+
+      /* Create a STUN server context for this socket */
+      snprintf(label, sizeof(label), "server(%s)", addrs[i].as_string);
+      if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server))
+        ABORT(r);
+      if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
+        ABORT(r);
+
+      STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
+    }
+    isock=0;
+
+
+    /* count the candidates that will be initialized */
+    cand=TAILQ_FIRST(&component->candidates);
+    if(!cand){
+      r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create any valid candidates");
+      ABORT(R_NOT_FOUND);
+    }
+
+    while(cand){
+      ctx->uninitialized_candidates++;
+      cand=TAILQ_NEXT(cand,entry_comp);
+    }
+
+    /* Now initialize all the candidates */
+    cand=TAILQ_FIRST(&component->candidates);
+    while(cand){
+      if(cand->state!=NR_ICE_CAND_STATE_INITIALIZING){
+        if(r=nr_ice_candidate_initialize(cand,nr_ice_initialize_finished_cb,ctx)){
+          if(r!=R_WOULDBLOCK){
+            cand->state=NR_ICE_CAND_STATE_FAILED;
+          }
+        }
+      }
+      cand=TAILQ_NEXT(cand,entry_comp);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+/* Prune redundant candidates. We use an n^2 algorithm for now.
+
+   This algorithm combined with the other algorithms, favors
+   host > srflx > relay
+
+   This actually won't prune relayed in the very rare
+   case that relayed is the same. Not relevant in practice.
+*/
+
+int nr_ice_component_prune_candidates(nr_ice_ctx *ctx, nr_ice_component *comp)
+  {
+    nr_ice_candidate *c1,*c1n,*c2;
+
+    c1=TAILQ_FIRST(&comp->candidates);
+    while(c1){
+      c1n=TAILQ_NEXT(c1,entry_comp);
+      if(c1->state!=NR_ICE_CAND_STATE_INITIALIZED){
+        r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Removing non-initialized candidate %s",
+          ctx->label,c1->label);
+        if (c1->state == NR_ICE_CAND_STATE_INITIALIZING) {
+          r_log(LOG_ICE,LOG_NOTICE, "ICE(%s): Removing candidate %s which is in INITIALIZING state",
+            ctx->label, c1->label);
+        }
+        TAILQ_REMOVE(&comp->candidates,c1,entry_comp);
+        comp->candidate_ct--;
+        TAILQ_REMOVE(&c1->isock->candidates,c1,entry_sock);
+        /* schedule this delete for later as we don't want to delete the underlying
+         * objects while in the middle of a callback on one of those objects */
+        NR_ASYNC_SCHEDULE(nr_ice_candidate_destroy_cb,c1);
+        goto next_c1;
+      }
+        
+      c2=TAILQ_NEXT(c1,entry_comp);
+
+      while(c2){
+        nr_ice_candidate *tmp;
+
+        if(!nr_transport_addr_cmp(&c1->base,&c2->base,NR_TRANSPORT_ADDR_CMP_MODE_ALL) && !nr_transport_addr_cmp(&c1->addr,&c2->addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL)){
+          
+          if((c1->type == c2->type) ||
+            (c1->type==HOST && c2->type == SERVER_REFLEXIVE) ||
+            (c2->type==HOST && c1->type == SERVER_REFLEXIVE)){
+            
+            /* OK these are redundant. Remove the lower pri one */
+            tmp=c2;
+            c2=TAILQ_NEXT(c2,entry_comp);
+            if(c1n==tmp)
+              c1n=c2;
+            
+            r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Removing redundant candidate %s",
+              ctx->label,tmp->label);
+            
+            TAILQ_REMOVE(&comp->candidates,tmp,entry_comp);
+            comp->candidate_ct--;
+            TAILQ_REMOVE(&tmp->isock->candidates,tmp,entry_sock);
+            
+            nr_ice_candidate_destroy(&tmp);
+          }
+        }
+        else{
+          c2=TAILQ_NEXT(c2,entry_comp);
+        }
+      }
+    next_c1:     
+      c1=c1n;
+    }
+        
+    return(0);
+  }
+
+/* Section 7.2.1 */
+static int nr_ice_component_stun_server_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *error)
+  {
+    nr_ice_component *comp=cb_arg;
+    nr_ice_cand_pair *pair;
+    nr_ice_candidate *pcand=0;
+    nr_transport_addr local_addr;
+    nr_stun_message *sreq=req->request;
+    nr_stun_message_attribute *attr;
+    int component_id_matched;
+    int local_addr_matched;
+    int remote_addr_matched;
+    nr_ice_cand_pair *found_invalid=0;
+    int r=0,_status;
+
+    assert(sock!=0);
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)(%d): received request from %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,req->src_addr.as_string);
+    
+    /* Check for role conficts (7.2.1.1) */
+    if(comp->stream->pctx->controlling){
+      if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLING,&attr)){
+        /* OK, there is a conflict. Who's right? */
+        r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): role conflict, both controlling",comp->stream->pctx->label);
+
+        if(attr->u.ice_controlling > comp->stream->pctx->tiebreaker){
+          /* They are: switch */
+          r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): switching to controlled",comp->stream->pctx->label);
+
+          comp->stream->pctx->controlling=0;
+        }
+        else {
+          /* We are: throw an error */
+          r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
+
+          *error=487;
+          ABORT(R_REJECTED); 
+        }
+      }
+    }
+    else{
+      if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_ICE_CONTROLLED,&attr)){
+        /* OK, there is a conflict. Who's right? */
+        r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): role conflict, both controlled",comp->stream->pctx->label);
+        
+        if(attr->u.ice_controlling < comp->stream->pctx->tiebreaker){
+          r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): switching to controlling",comp->stream->pctx->label);
+
+          /* They are: switch */
+          comp->stream->pctx->controlling=1;
+        }
+        else {
+          /* We are: throw an error */
+          r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): returning 487 role conflict",comp->stream->pctx->label);
+
+          *error=487;
+          ABORT(R_REJECTED); 
+        }
+      }
+    }
+
+    /* Find the candidate pair that this maps to */
+    if(r=nr_socket_getaddr(sock,&local_addr)) {
+      *error=500;
+      ABORT(r);
+    }
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): This STUN request appears to map to local addr",comp->stream->pctx->label,local_addr.as_string);
+
+    pair=TAILQ_FIRST(&comp->stream->check_list);
+    while(pair){
+      component_id_matched = 0;
+      local_addr_matched = 0;
+      remote_addr_matched = 0;
+
+      if(pair->remote->component->component_id!=comp->component_id)
+        goto next_pair;
+      component_id_matched = 1;
+      
+      if(nr_transport_addr_cmp(&pair->local->base,&local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
+        goto next_pair;
+      local_addr_matched=1;
+
+
+      if(nr_transport_addr_cmp(&pair->remote->addr,&req->src_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
+        goto next_pair;
+      remote_addr_matched = 1;
+
+      if(pair->state==NR_ICE_PAIR_STATE_FAILED ||
+        pair->state==NR_ICE_PAIR_STATE_FAILED){
+        found_invalid=pair;
+        goto next_pair;
+      }
+
+      if (local_addr_matched && remote_addr_matched){
+        r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): Found a matching pair: %s",comp->stream->pctx->label,pair->as_string);
+        break; /* OK, this is a known pair */
+      }
+
+    next_pair:
+      pair=TAILQ_NEXT(pair,entry);
+    }
+
+    if(!pair){
+      if(!found_invalid){
+        /* First find our local component candidate */
+        nr_ice_candidate *cand;
+      
+        r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): no matching pair",comp->stream->pctx->label);
+        cand=TAILQ_FIRST(&comp->local_component->candidates);
+        while(cand){
+          if(!nr_transport_addr_cmp(&cand->addr,&local_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
+            break;
+
+          cand=TAILQ_NEXT(cand,entry_comp);
+        }
+
+        /* Well, this really shouldn't happen, but it's an error from the
+           other side, so we just throw an error and keep going */
+        if(!cand){
+          r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): stun request to unknown local address %s, discarding",comp->stream->pctx->label,local_addr.as_string);
+
+          *error=400;
+          ABORT(R_NOT_FOUND);
+        }
+
+        /* We now need to make a peer reflexive */
+        if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) {
+          *error=(r==R_NO_MEMORY)?500:400;
+          ABORT(r);
+        }
+        if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY,&attr)){
+          r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label);
+          *error=487;
+          ABORT(R_BAD_DATA);
+        }
+        pcand->priority=attr->u.priority;
+        pcand->state=NR_ICE_CAND_PEER_CANDIDATE_PAIRED;;
+        TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp);
+
+        if(r=nr_ice_candidate_pair_create(comp->stream->pctx,cand,pcand,
+             &pair)) {
+          *error=(r==R_NO_MEMORY)?500:400;
+          ABORT(r);
+        }
+        nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_FROZEN);        
+      
+        if(r=nr_ice_candidate_pair_insert(&comp->stream->check_list,pair)) {
+          *error=(r==R_NO_MEMORY)?500:400;
+          ABORT(r);
+        }
+      
+        pcand=0;
+      }
+      else{
+        /* OK, there was a pair, it's just invalid: According to Section
+           7.2.1.4, we need to resurrect it 
+        */
+        if(found_invalid->state == NR_ICE_PAIR_STATE_FAILED){
+          pair=found_invalid;
+
+          r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): received STUN check on invalid pair %s: resurrecting",comp->stream->pctx->label,pair->as_string);
+          nr_ice_candidate_pair_set_state(pair->pctx,pair,NR_ICE_PAIR_STATE_WAITING);
+        }
+        else{
+          /* This shouldn't happen */
+          r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): received STUN check on invalid pair %s but not in FAILED state",comp->stream->pctx->label,pair->as_string);
+          *error=500;
+          ABORT(R_BAD_DATA);
+        }
+      }
+    }
+
+    /* OK, we've got a pair to work with. Turn it on */
+    if(nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_USE_CANDIDATE,0)){
+      if(comp->stream->pctx->controlling){
+        r_log(LOG_ICE,LOG_ERR,"ICE-PEER(%s): Peer sent USE-CANDIDATE but is controlled",comp->stream->pctx->label);
+      }
+      else{
+        /* If this is the first time we've noticed this is nominated...*/
+        pair->peer_nominated=1;
+
+        if(pair->state==NR_ICE_PAIR_STATE_SUCCEEDED && !pair->nominated){
+          pair->nominated=1;
+
+          if(r=nr_ice_component_nominated_pair(pair->remote->component, pair)) {
+            *error=(r==R_NO_MEMORY)?500:400;
+            ABORT(r);
+          }
+        }
+      }
+    }
+    assert(pair != 0);
+
+    if(r=nr_ice_candidate_pair_do_triggered_check(comp->stream->pctx,pair)) {
+      *error=(r==R_NO_MEMORY)?500:400;
+      ABORT(r);
+    }
+
+    _status=0;
+  abort:
+    if(_status){
+      nr_ice_candidate_destroy(&pcand);
+      assert(*error != 0);
+      if(r!=R_NO_MEMORY) assert(*error != 500);
+    }
+    return(_status);
+  }
+
+int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp)
+  {
+    nr_ice_candidate *lcand,*pcand;
+    nr_ice_cand_pair *pair=0;
+    nr_ice_socket *isock;
+    int r,_status;
+    char codeword[5];
+
+    r_log(LOG_ICE,LOG_DEBUG,"Pairing candidates======");
+    /* Create the candidate pairs */
+    lcand=TAILQ_FIRST(&lcomp->candidates);
+    while(lcand){
+      nr_ice_compute_codeword(lcand->label,strlen(lcand->label),codeword);
+      r_log(LOG_ICE,LOG_DEBUG,"Examining local candidate %s:%s",codeword,lcand->label);
+
+      switch(lcand->type){
+        case HOST:
+          break;
+        case SERVER_REFLEXIVE:
+          /* Don't actually pair these candidates */
+          goto next_cand;
+          break;
+        case PEER_REFLEXIVE:
+          UNIMPLEMENTED;
+          break;
+        case RELAYED:
+          break;
+        default:
+          assert(0);
+          ABORT(R_INTERNAL);
+          break;
+      }
+      
+      /* PAIR with each peer*/
+      if(TAILQ_EMPTY(&pcomp->candidates)) {
+          /* can happen if our peer proposes no (or all bogus) candidates */
+          goto next_cand;
+      }
+      pcand=TAILQ_FIRST(&pcomp->candidates);
+      while(pcand){
+        /* Only pair peer candidates which have not yet been paired.
+           This allows "trickle ICE". (Not yet standardized, but
+           part of WebRTC).
+
+           TODO(ekr@rtfm.com): Add refernece to the spec when there
+           is one.
+         */
+        if (pcand->state = NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED) {
+          nr_ice_compute_codeword(pcand->label,strlen(pcand->label),codeword);
+          r_log(LOG_ICE,LOG_DEBUG,"Examining peer candidate %s:%s",codeword,pcand->label);
+          
+          if(r=nr_ice_candidate_pair_create(pctx,lcand,pcand,&pair))
+            ABORT(r);
+          
+          if(r=nr_ice_candidate_pair_insert(&pcomp->stream->check_list,
+              pair))
+            ABORT(r);
+        }
+        pcand=TAILQ_NEXT(pcand,entry_comp);
+      }
+    
+      if(!pair)
+        ABORT(R_INTERNAL);
+
+      /* Add the stun username/password pair from the last pair (any 
+         would do) to the stun contexts */
+      isock=STAILQ_FIRST(&lcomp->sockets);
+      while(isock){
+        if(r=nr_stun_server_add_client(isock->stun_server,pctx->label,
+           pair->r2l_user,&pair->r2l_pwd,nr_ice_component_stun_server_cb,pcomp))
+          ABORT(r);
+
+        isock=STAILQ_NEXT(isock,entry);
+      }
+
+    next_cand:
+      lcand=TAILQ_NEXT(lcand,entry_comp);
+    } 
+
+    /* Mark all peer candidates as paired */
+    pcand=TAILQ_FIRST(&pcomp->candidates);
+    while(pcand){
+      pcand->state = NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
+      
+      pcand=TAILQ_NEXT(pcand,entry_comp);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
+  {
+    int r,_status;
+    int fire_cb=0;
+    nr_ice_cand_pair *p2;
+
+    if(!comp->nominated)
+      fire_cb=1;
+
+    /* Are we changing what the nominated pair is? */
+    if(comp->nominated){
+      if(comp->nominated->priority > pair->priority)
+        return(0);
+      r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): replacing pair %s with pair %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,comp->nominated->as_string,pair->as_string);
+    }
+
+    /* Set the new nominated pair */
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): nominated pair is %s (0x%p)",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->as_string,pair);
+    comp->state=NR_ICE_COMPONENT_NOMINATED;
+    comp->nominated=pair;
+    comp->active=pair;
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling all pairs but %s (0x%p)",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->as_string,pair);
+
+    /* OK, we need to cancel off everything on this component */
+    p2=TAILQ_FIRST(&comp->stream->check_list);
+    while(p2){
+      if((p2 != pair) && (p2->remote->component->component_id == comp->component_id)){
+        r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling pair %s (0x%p)",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->as_string,p2);
+        
+        if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2))
+          ABORT(r);
+      }
+
+      p2=TAILQ_NEXT(p2,entry);
+    }
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/comp(%d): cancelling done",comp->stream->pctx->label,comp->stream->label,comp->component_id);
+
+    if(r=nr_ice_media_stream_component_nominated(comp->stream,comp))
+      ABORT(r);
+      
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair)
+  {
+    int r,_status;
+    nr_ice_cand_pair *p2;
+
+    assert(pair->state == NR_ICE_PAIR_STATE_FAILED);
+
+    p2=TAILQ_FIRST(&comp->stream->check_list);
+    while(p2){
+      if(comp->component_id==p2->local->component_id){
+        switch(p2->state){
+        case NR_ICE_PAIR_STATE_FROZEN:
+        case NR_ICE_PAIR_STATE_WAITING:
+        case NR_ICE_PAIR_STATE_IN_PROGRESS:
+            /* answer component status cannot be determined yet */
+            goto done;
+            break;
+        case NR_ICE_PAIR_STATE_SUCCEEDED:
+            /* the component will succeed */
+            goto done;
+            break;
+        case NR_ICE_PAIR_STATE_FAILED:
+        case NR_ICE_PAIR_STATE_CANCELLED:
+            /* states that will never be recovered from */
+            break;
+        default:
+            assert(0);
+            break;
+        }
+      }
+
+      p2=TAILQ_NEXT(p2,entry);
+    }
+
+    /* all the pairs in the component are in their final states with
+     * none of them being SUCCEEDED, so the component fails entirely,
+     * tell the media stream that this component has failed */
+
+    if(r=nr_ice_media_stream_component_failed(comp->stream,comp))
+      ABORT(r);
+
+  done:
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp)
+  {
+    nr_ice_cand_pair **pairs=0;
+    int ct=0;
+    nr_ice_cand_pair *pair;
+    int r,_status;
+    
+    /* Size the array */
+    pair=TAILQ_FIRST(&comp->stream->check_list);
+    while(pair){
+      if (comp->component_id == pair->local->component_id)
+          ct++;
+
+      pair=TAILQ_NEXT(pair,entry);
+    }
+
+    /* Make and fill the array */
+    if(!(pairs=RCALLOC(sizeof(nr_ice_cand_pair *)*ct)))
+      ABORT(R_NO_MEMORY);
+
+    ct=0;
+    pair=TAILQ_FIRST(&comp->stream->check_list);
+    while(pair){
+      if (comp->component_id == pair->local->component_id)
+          pairs[ct++]=pair;
+
+      pair=TAILQ_NEXT(pair,entry);
+    }
+
+    if (pctx->handler) {
+      if(r=pctx->handler->vtbl->select_pair(pctx->handler->obj,
+        comp->stream,comp->component_id,pairs,ct))
+        ABORT(r);
+    }
+
+    _status=0;
+  abort:
+    RFREE(pairs);
+    return(_status);
+  }
+
+
+static void nr_ice_component_keepalive_cb(NR_SOCKET s, int how, void *cb_arg)
+  {
+    nr_ice_component *comp=cb_arg;
+    UINT4 keepalive_timeout;
+
+    assert(comp->keepalive_ctx);
+
+    if(NR_reg_get_uint4(NR_ICE_REG_KEEPALIVE_TIMER,&keepalive_timeout)){
+      keepalive_timeout=15000; /* Default */
+    }
+
+
+    if(comp->keepalive_needed)
+      nr_stun_client_force_retransmit(comp->keepalive_ctx);
+
+    comp->keepalive_needed=1;
+    NR_ASYNC_TIMER_SET(keepalive_timeout,nr_ice_component_keepalive_cb,cb_arg,&comp->keepalive_timer);
+  }
+
+
+/* Close the underlying sockets for everything but the nominated candidate */
+int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp)
+  {
+    nr_ice_socket *isock=0;
+    int r,_status;
+    nr_ice_socket *s1,*s2;
+
+    if(rcomp->state==NR_ICE_COMPONENT_NOMINATED){
+      assert(rcomp->active == rcomp->nominated);
+      isock=rcomp->nominated->local->isock;
+    }
+
+    STAILQ_FOREACH_SAFE(s1, &lcomp->sockets, entry, s2){
+      if(s1!=isock){
+        STAILQ_REMOVE(&lcomp->sockets,s1,nr_ice_socket_,entry);
+        nr_ice_socket_destroy(&s1);
+      }
+    }
+
+    /* Set up the keepalives for the chosen socket */
+    if(r=nr_stun_client_ctx_create("keepalive",rcomp->nominated->local->osock,
+      &rcomp->nominated->remote->addr,0,&rcomp->keepalive_ctx))
+      ABORT(r);
+    if(r=nr_stun_client_start(rcomp->keepalive_ctx,NR_STUN_CLIENT_MODE_KEEPALIVE,0,0))
+      ABORT(r);
+    nr_ice_component_keepalive_cb(0,0,rcomp);
+
+
+    _status=0;
+  abort:
+
+    return(_status);
+  }
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.h
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _ice_component_h
+#define _ice_component_h
+#ifdef __cplusplus
+using namespace std;
+extern "C" {
+#endif /* __cplusplus */
+
+struct nr_ice_component_ {
+  int state;
+#define NR_ICE_COMPONENT_RUNNING            1
+#define NR_ICE_COMPONENT_NOMINATED          2
+#define NR_ICE_COMPONENT_FAILED             3
+  struct nr_ice_ctx_ *ctx;
+  struct nr_ice_media_stream_ *stream;
+  nr_ice_component *local_component;
+
+  int component_id;
+  nr_ice_socket_head sockets;
+  nr_ice_candidate_head candidates;
+  int candidate_ct;
+  
+  int valid_pairs;
+  struct nr_ice_cand_pair_ *nominated; /* Highest priority nomninated pair */
+  struct nr_ice_cand_pair_ *active;
+
+  int keepalive_needed;
+  void *keepalive_timer;
+  nr_stun_client_ctx *keepalive_ctx;
+
+  STAILQ_ENTRY(nr_ice_component_)entry;
+};
+
+typedef STAILQ_HEAD(nr_ice_component_head_,nr_ice_component_) nr_ice_component_head;
+
+int nr_ice_component_create(struct nr_ice_media_stream_ *stream, int component_id, nr_ice_component **componentp);
+int nr_ice_component_destroy(nr_ice_component **componentp);
+int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *component);
+int nr_ice_component_prune_candidates(nr_ice_ctx *ctx, nr_ice_component *comp);
+int nr_ice_component_pair_candidates(nr_ice_peer_ctx *pctx, nr_ice_component *lcomp,nr_ice_component *pcomp);
+int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
+int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
+int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp);
+int nr_ice_component_set_failed(nr_ice_component *comp);
+int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
@@ -0,0 +1,540 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: ice_ctx.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
+
+#include <csi_platform.h>
+#include <assert.h>
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <sys/queue.h>
+#include <string.h>
+#include <nr_api.h>
+#include <registry.h>
+#include "stun.h"
+#include "ice_ctx.h"
+#include "ice_reg.h"
+#include "nr_crypto.h"
+#include "async_timer.h"
+#include "util.h"
+
+
+int LOG_ICE = 0;
+
+static int nr_ice_random_string(char *str, int len);
+static int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out);
+#ifdef USE_TURN
+static int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out);
+#endif /* USE_TURN */
+static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg);
+
+int nr_ice_fetch_stun_servers(int ct, nr_ice_stun_server **out)
+  {
+    int r,_status;
+    nr_ice_stun_server *servers = 0;
+    int i;
+    NR_registry child;
+    char *addr=0;
+    UINT2 port;
+    in_addr_t addr_int;
+
+    if(!(servers=RCALLOC(sizeof(nr_ice_stun_server)*ct)))
+      ABORT(R_NO_MEMORY);
+
+    for(i=0;i<ct;i++){
+      if(r=NR_reg_get_child_registry(NR_ICE_REG_STUN_SRV_PRFX,i,child))
+        ABORT(r);
+      /* Assume we have a v4 addr for now */
+      if(r=NR_reg_alloc2_string(child,"addr",&addr))
+        ABORT(r);
+      addr_int=inet_addr(addr);
+      if(addr_int==INADDR_NONE){
+        r_log(LOG_ICE,LOG_ERR,"Invalid address %s",addr);
+        ABORT(R_BAD_ARGS);
+      }
+      if(r=NR_reg_get2_uint2(child,"port",&port)) {
+        if (r != R_NOT_FOUND)
+          ABORT(r);
+        port = 3478;
+      }
+      if(r=nr_ip4_port_to_transport_addr(ntohl(addr_int), port, IPPROTO_UDP, 
+        &servers[i].addr))
+        ABORT(r);
+      servers[i].index=i;
+
+      RFREE(addr);
+      addr=0;
+    }
+
+    *out = servers;
+
+    _status=0;
+  abort:
+    RFREE(addr);
+    if (_status) RFREE(servers);
+    return(_status);
+  }
+
+#ifdef USE_TURN
+int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out)
+  {
+    int r,_status;
+    nr_ice_turn_server *servers = 0;
+    int i;
+    NR_registry child;
+    char *addr=0;
+    UINT2 port;
+    in_addr_t addr_int;
+    Data data={0};
+
+    if(!(servers=RCALLOC(sizeof(nr_ice_turn_server)*ct)))
+      ABORT(R_NO_MEMORY);
+
+    for(i=0;i<ct;i++){
+      if(r=NR_reg_get_child_registry(NR_ICE_REG_TURN_SRV_PRFX,i,child))
+        ABORT(r);
+      /* Assume we have a v4 addr for now */
+      if(r=NR_reg_alloc2_string(child,"addr",&addr))
+        ABORT(r);
+      addr_int=inet_addr(addr);
+      if(addr_int==INADDR_NONE){
+        r_log(LOG_ICE,LOG_ERR,"Invalid address %s",addr);
+        ABORT(R_BAD_ARGS);
+      }
+      if(r=NR_reg_get2_uint2(child,"port",&port)) {
+        if (r != R_NOT_FOUND)
+          ABORT(r);
+        port = 3478;
+      }
+      if(r=nr_ip4_port_to_transport_addr(ntohl(addr_int), port, IPPROTO_UDP, 
+        &servers[i].turn_server.addr))
+        ABORT(r);
+
+      if(r=NR_reg_get2_uint4(child,NR_ICE_REG_TURN_SRV_BANDWIDTH,&servers[i].bandwidth_kbps))
+        if(r!=R_NOT_FOUND)
+          ABORT(r);
+      if(r=NR_reg_get2_uint4(child,NR_ICE_REG_TURN_SRV_LIFETIME,&servers[i].lifetime_secs))
+        if(r!=R_NOT_FOUND)
+          ABORT(r);
+
+      if(r=NR_reg_alloc2_string(child,NR_ICE_REG_TURN_SRV_USERNAME,&servers[i].username)){
+        if(r!=R_NOT_FOUND)
+          ABORT(r);
+      }
+
+      if(r=NR_reg_alloc2_data(child,NR_ICE_REG_TURN_SRV_PASSWORD,&data)){
+        if(r!=R_NOT_FOUND)
+          ABORT(r);
+      }
+      else {
+        servers[i].password=RCALLOC(sizeof(*servers[i].password)); 
+        if(!servers[i].password)
+          ABORT(R_NO_MEMORY);
+        servers[i].password->data = data.data;
+        servers[i].password->len = data.len;
+        data.data=0;
+      }
+
+      servers[i].turn_server.index=i;
+
+      RFREE(addr);
+      addr=0;
+    }
+
+    *out = servers;
+
+    _status=0;
+  abort:
+    RFREE(data.data);
+    RFREE(addr);
+    if (_status) RFREE(servers);
+    return(_status);
+  }
+#endif /* USE_TURN */
+
+int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp)
+  {
+    nr_ice_ctx *ctx=0;
+    int r,_status;
+    char buf[100];
+
+    if(r=r_log_register("ice", &LOG_ICE))
+      ABORT(r);
+
+    if(!(ctx=RCALLOC(sizeof(nr_ice_ctx))))
+      ABORT(R_NO_MEMORY);
+
+    ctx->flags=flags;
+
+    if(!(ctx->label=r_strdup(label)))
+      ABORT(R_NO_MEMORY);
+
+    if(r=nr_ice_random_string(buf,8))
+      ABORT(r);
+    if(!(ctx->ufrag=r_strdup(buf)))
+      ABORT(r);
+    if(r=nr_ice_random_string(buf,32))
+      ABORT(r);
+    if(!(ctx->pwd=r_strdup(buf)))
+      ABORT(r);
+    
+    /* Get the STUN servers */
+    if(r=NR_reg_get_child_count(NR_ICE_REG_STUN_SRV_PRFX,
+      (unsigned int *)&ctx->stun_server_ct)||ctx->stun_server_ct==0) {
+      r_log(LOG_ICE,LOG_NOTICE,"No STUN servers specified");
+      ctx->stun_server_ct=0;
+    }
+
+    /* 255 is the max for our priority algorithm */
+    if(ctx->stun_server_ct>255){
+      r_log(LOG_ICE,LOG_WARNING,"Too many STUN servers specified: max=255");
+      ctx->stun_server_ct=255;
+    }
+
+    if(r=nr_ice_fetch_stun_servers(ctx->stun_server_ct,&ctx->stun_servers)){
+      r_log(LOG_ICE,LOG_ERR,"Couldn't load STUN servers from registry");
+      ctx->turn_server_ct=0;
+      ABORT(r);
+    }
+
+#ifdef USE_TURN
+    /* Get the TURN servers */
+    if(r=NR_reg_get_child_count(NR_ICE_REG_TURN_SRV_PRFX,
+      (unsigned int *)&ctx->turn_server_ct)||ctx->turn_server_ct==0) {
+      r_log(LOG_ICE,LOG_NOTICE,"No TURN servers specified");
+      ctx->turn_server_ct=0;
+    }
+#else
+    ctx->turn_server_ct=0;
+#endif /* USE_TURN */
+
+    /* 255 is the max for our priority algorithm */
+    if((ctx->stun_server_ct+ctx->turn_server_ct)>255){
+      r_log(LOG_ICE,LOG_WARNING,"Too many STUN/TURN servers specified: max=255");
+      ctx->turn_server_ct=255-ctx->stun_server_ct;
+    }
+
+#ifdef USE_TURN
+    if(r=nr_ice_fetch_turn_servers(ctx->turn_server_ct,&ctx->turn_servers)){
+      ctx->turn_server_ct=0;
+      r_log(LOG_ICE,LOG_ERR,"Couldn't load TURN servers from registry");
+      ABORT(r);
+    }
+#endif /* USE_TURN */
+
+
+    ctx->Ta = 20;
+
+    STAILQ_INIT(&ctx->streams);
+    STAILQ_INIT(&ctx->sockets);
+    STAILQ_INIT(&ctx->foundations);
+    STAILQ_INIT(&ctx->peers);
+    STAILQ_INIT(&ctx->ids);
+
+    *ctxp=ctx;
+
+    _status=0;
+  abort:
+    if(_status)
+      nr_ice_ctx_destroy_cb(0,0,ctx);
+
+    return(_status);
+  }
+
+static void nr_ice_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg)
+  {
+    nr_ice_ctx *ctx=cb_arg;
+    nr_ice_foundation *f1,*f2;
+    nr_ice_media_stream *s1,*s2;
+    int i;
+    nr_ice_stun_id *id1,*id2;
+
+    RFREE(ctx->label);
+
+    RFREE(ctx->stun_servers);
+
+    for (i = 0; i < ctx->turn_server_ct; i++) {
+        RFREE(ctx->turn_servers[i].username);
+        r_data_destroy(&ctx->turn_servers[i].password);
+    }
+    RFREE(ctx->turn_servers);
+    
+    f1=STAILQ_FIRST(&ctx->foundations);
+    while(f1){
+      f2=STAILQ_NEXT(f1,entry);
+      RFREE(f1);
+      f1=f2;
+    }
+    RFREE(ctx->pwd);
+    RFREE(ctx->ufrag);
+
+    STAILQ_FOREACH_SAFE(s1, &ctx->streams, entry, s2){
+      STAILQ_REMOVE(&ctx->streams,s1,nr_ice_media_stream_,entry);
+      nr_ice_media_stream_destroy(&s1);
+    }
+
+    STAILQ_FOREACH_SAFE(id1, &ctx->ids, entry, id2){
+      STAILQ_REMOVE(&ctx->ids,id1,nr_ice_stun_id_,entry);
+      RFREE(id1);
+    }
+
+    RFREE(ctx);
+  }
+
+int nr_ice_ctx_destroy(nr_ice_ctx **ctxp)
+  {
+    if(!ctxp || !*ctxp)
+      return(0);
+
+    NR_ASYNC_SCHEDULE(nr_ice_ctx_destroy_cb,*ctxp);
+
+    *ctxp=0;
+    
+    return(0);
+  }
+
+void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg)
+  {
+    nr_ice_ctx *ctx=cb_arg;
+
+/*    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Candidate %s %s",ctx->label,
+      cand->label, cand->state==NR_ICE_CAND_STATE_INITIALIZED?"INITIALIZED":"FAILED");
+*/
+    ctx->uninitialized_candidates--;
+
+    if(ctx->uninitialized_candidates==0){
+      r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): All candidates initialized",ctx->label);
+      ctx->state=NR_ICE_STATE_INITIALIZED;
+      ctx->done_cb(0,0,ctx->cb_arg);
+    }
+    else {
+      r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Waiting for %d candidates to be initialized",ctx->label, ctx->uninitialized_candidates);
+    }
+  }
+
+int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg)
+  {
+    int r,_status;
+    nr_ice_media_stream *stream;
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Initializing candidates",ctx->label);
+    ctx->state=NR_ICE_STATE_INITIALIZING;
+    ctx->done_cb=done_cb;
+    ctx->cb_arg=cb_arg;
+
+    if(STAILQ_EMPTY(&ctx->streams)) {
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): Missing streams to initialize",ctx->label);
+      ABORT(R_BAD_ARGS);
+    }
+
+    /* Initialize all the media stream/component pairs */
+    stream=STAILQ_FIRST(&ctx->streams);
+    while(stream){
+      if(r=nr_ice_media_stream_initialize(ctx,stream))
+        ABORT(r);
+      
+      stream=STAILQ_NEXT(stream,entry);
+    }
+
+    if(ctx->uninitialized_candidates)
+      ABORT(R_WOULDBLOCK);
+    
+    
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp)
+  {
+    int r,_status;
+
+    if(r=nr_ice_media_stream_create(ctx,label,components,streamp))
+      ABORT(r);
+    
+    STAILQ_INSERT_TAIL(&ctx->streams,*streamp,entry);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp)
+  {
+    char **attrs=0;
+    int _status;
+    char *tmp=0;
+
+    if(!(attrs=RCALLOC(sizeof(char *)*2)))
+      ABORT(R_NO_MEMORY);
+    
+    if(!(tmp=RMALLOC(100)))
+      ABORT(R_NO_MEMORY);
+    snprintf(tmp,100,"ice-ufrag:%s",ctx->ufrag);
+    attrs[0]=tmp;
+
+    if(!(tmp=RMALLOC(100)))
+      ABORT(R_NO_MEMORY);
+    snprintf(tmp,100,"ice-pwd:%s",ctx->pwd);
+    attrs[1]=tmp;
+
+    *attrctp=2;
+    *attrsp=attrs;
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+static int nr_ice_random_string(char *str, int len)
+  {
+    unsigned char bytes[100];
+    int needed;
+    int r,_status;
+
+    if(len%2) ABORT(R_BAD_ARGS);
+    needed=len/2;
+
+    if(needed>sizeof(bytes)) ABORT(R_BAD_ARGS);
+
+    //memset(bytes,0,needed);
+
+    if(r=nr_crypto_random_bytes(bytes,needed))
+      ABORT(r);
+    
+    if(r=nr_bin2hex(bytes,needed,(unsigned char *)str))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+/* This is incredibly annoying: we now have a datagram but we don't
+   know which peer it's from, and we need to be able to tell the 
+   API user. So, offer it to each peer and if one bites, assume
+   the others don't want it 
+*/
+int nr_ice_ctx_deliver_packet(nr_ice_ctx *ctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len)
+  {
+    nr_ice_peer_ctx *pctx;
+    int r;
+
+    pctx=STAILQ_FIRST(&ctx->peers);
+    while(pctx){
+      r=nr_ice_peer_ctx_deliver_packet_maybe(pctx, comp, source_addr, data, len);
+      if(!r)
+        break;
+
+      pctx=STAILQ_NEXT(pctx,entry);
+    }
+
+    if(!pctx)
+      r_log(LOG_ICE,LOG_INFO,"ICE(%s): Packet received from %s which doesn't match any known peer",ctx->label,source_addr->as_string);
+    
+    return(0);
+  }
+
+int nr_ice_ctx_is_known_id(nr_ice_ctx *ctx, UCHAR id[12])
+  {
+    nr_ice_stun_id *xid;
+
+    xid=STAILQ_FIRST(&ctx->ids);
+    while(xid){
+      if (!memcmp(xid->id, id, 12))
+          return 1;
+
+      xid=STAILQ_NEXT(xid,entry);
+    }
+
+    return 0;
+  }
+
+int nr_ice_ctx_remember_id(nr_ice_ctx *ctx, nr_stun_message *msg)
+{
+    int _status;
+    nr_ice_stun_id *xid;
+
+    xid = RCALLOC(sizeof(*xid));
+    if (!xid)
+        ABORT(R_NO_MEMORY);
+
+    assert(sizeof(xid->id) == sizeof(msg->header.id));
+    memcpy(xid->id, &msg->header.id, sizeof(xid->id));
+
+    STAILQ_INSERT_TAIL(&ctx->ids,xid,entry);
+
+    _status=0;
+  abort:
+    return(_status);
+}
+
+
+/* Clean up some of the resources (mostly file descriptors) used 
+   by candidates we didn't choose. Note that this still leaves
+   a fair amount of non-system stuff floating around. This gets
+   cleaned up when you destroy the ICE ctx */
+int nr_ice_ctx_finalize(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx)
+  {
+    nr_ice_media_stream *lstr,*rstr;
+
+    r_log(LOG_ICE,LOG_DEBUG,"Finalizing ICE ctx %s, peer=%s",ctx->label,pctx->label);
+    /* 
+       First find the peer stream, if any 
+    */
+    lstr=STAILQ_FIRST(&ctx->streams);
+    while(lstr){
+      rstr=STAILQ_FIRST(&pctx->peer_streams);
+      
+      while(rstr){
+        if(rstr->local_stream==lstr)
+          break;
+
+        rstr=STAILQ_NEXT(rstr,entry);
+      }
+      
+      nr_ice_media_stream_finalize(lstr,rstr);
+
+      lstr=STAILQ_NEXT(lstr,entry);
+    }
+
+    return(0);
+  }
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
@@ -0,0 +1,157 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _ice_ctx_h
+#define _ice_ctx_h
+#ifdef __cplusplus
+using namespace std;
+extern "C" {
+#endif /* __cplusplus */
+
+/* Not good practice but making includes simpler */
+#include "transport_addr.h"
+#include "nr_socket.h"
+#include "stun_client_ctx.h"
+#include "stun_server_ctx.h"
+#include "turn_client_ctx.h"
+
+typedef struct nr_ice_stun_server_ {
+  nr_transport_addr addr;
+  int index;
+} nr_ice_stun_server;
+
+typedef struct nr_ice_turn_server_ {
+    nr_ice_stun_server    turn_server;
+    UINT4                 bandwidth_kbps;
+    UINT4                 lifetime_secs;
+    char                 *username;
+    Data                 *password;
+} nr_ice_turn_server;
+
+typedef struct nr_ice_foundation_ {
+  int index;
+  
+  nr_transport_addr addr;
+  int type;
+  nr_ice_stun_server *stun_server;
+
+  STAILQ_ENTRY(nr_ice_foundation_) entry;
+} nr_ice_foundation;
+
+typedef STAILQ_HEAD(nr_ice_foundation_head_,nr_ice_foundation_) nr_ice_foundation_head;
+
+typedef TAILQ_HEAD(nr_ice_candidate_head_,nr_ice_candidate_) nr_ice_candidate_head;
+typedef TAILQ_HEAD(nr_ice_cand_pair_head_,nr_ice_cand_pair_) nr_ice_cand_pair_head;
+typedef struct nr_ice_component_ nr_ice_component;
+typedef struct nr_ice_media_stream_ nr_ice_media_stream;
+typedef struct nr_ice_ctx_ nr_ice_ctx;
+typedef struct nr_ice_peer_ctx_ nr_ice_peer_ctx;
+typedef struct nr_ice_candidate_ nr_ice_candidate;
+typedef struct nr_ice_cand_pair_ nr_ice_cand_pair;
+
+#include "ice_socket.h"
+#include "ice_component.h"
+#include "ice_media_stream.h"
+#include "ice_candidate.h"
+#include "ice_candidate_pair.h"
+#include "ice_handler.h"
+#include "ice_peer_ctx.h"
+
+typedef struct nr_ice_stun_id_ {
+  UCHAR id[12];
+
+  STAILQ_ENTRY(nr_ice_stun_id_) entry;
+} nr_ice_stun_id;
+
+typedef STAILQ_HEAD(nr_ice_stun_id_head_,nr_ice_stun_id_) nr_ice_stun_id_head;
+
+struct nr_ice_ctx_ {
+  UINT4 flags;
+  int state;
+#define NR_ICE_STATE_CREATED          1
+#define NR_ICE_STATE_INITIALIZING     2
+#define NR_ICE_STATE_INITIALIZED      3
+  char *label;
+  
+  char *ufrag;
+  char *pwd;
+
+  UINT4 Ta;
+
+  nr_ice_stun_server *stun_servers;           /* The list of stun servers */
+  int stun_server_ct;
+  nr_ice_turn_server *turn_servers;           /* The list of turn servers */
+  int turn_server_ct;
+
+  nr_ice_foundation_head foundations;
+  
+  nr_ice_media_stream_head streams;           /* Media streams */
+  int stream_ct;
+  nr_ice_socket_head sockets;                 /* The sockets we're using */
+  int uninitialized_candidates;  
+
+  UINT4 gather_rto;
+  UINT4 stun_delay;
+
+  nr_ice_peer_ctx_head peers;
+  nr_ice_stun_id_head ids;
+
+  NR_async_cb done_cb;
+  void *cb_arg;
+};
+
+int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp);
+#define NR_ICE_CTX_FLAGS_OFFERER                           1
+#define NR_ICE_CTX_FLAGS_ANSWERER                          (1<<1)
+#define NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION             (1<<2)
+#define NR_ICE_CTX_FLAGS_LITE                              (1<<3)
+
+int nr_ice_ctx_destroy(nr_ice_ctx **ctxp);
+int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg);
+int nr_ice_add_candidate(nr_ice_ctx *ctx, nr_ice_candidate *cand);
+void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg);
+int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp);
+int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp);
+int nr_ice_ctx_deliver_packet(nr_ice_ctx *ctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len);
+int nr_ice_ctx_is_known_id(nr_ice_ctx *ctx, UCHAR id[12]);
+int nr_ice_ctx_remember_id(nr_ice_ctx *ctx, nr_stun_message *msg);
+int nr_ice_ctx_finalize(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx);
+
+extern int LOG_ICE;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_handler.h
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _ice_h
+#define _ice_h
+#ifdef __cplusplus
+using namespace std;
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct nr_ice_handler_vtbl_ {
+  /* The checks on this media stream are done. The handler needs to 
+     select a single pair to proceed with (regular nomination).
+     Once this returns the check starts and the pair can be
+     written on. Use nr_ice_candidate_pair_select() to perform the
+     selection.
+     TODO: !ekr! is this right?
+  */
+  int (*select_pair)(void *obj,nr_ice_media_stream *stream, 
+int component_id, nr_ice_cand_pair **potentials,int potential_ct);
+
+  /* This media stream is ready to read/write (aggressive nomination).
+     May be called again if the nominated pair changes due to
+     ICE instability. TODO: !ekr! think about this
+  */
+  int (*stream_ready)(void *obj, nr_ice_media_stream *stream);
+
+  /* This media stream has failed */
+  int (*stream_failed)(void *obj, nr_ice_media_stream *stream);
+
+  /* ICE is completed for this peer ctx
+     if need_update is nonzero, a SIP update is required
+   */
+  int (*ice_completed)(void *obj, nr_ice_peer_ctx *pctx);
+
+  /* A message was delivered to us */
+  int (*msg_recvd)(void *obj, nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, int component_id, UCHAR *msg, int len);
+} nr_ice_handler_vtbl;
+
+typedef struct nr_ice_handler_ {
+  void *obj;
+  nr_ice_handler_vtbl *vtbl;
+} nr_ice_handler;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
@@ -0,0 +1,740 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: ice_media_stream.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
+
+#include <string.h>
+#include <assert.h>
+#include <nr_api.h>
+#include <r_assoc.h>
+#include <async_timer.h>
+#include "ice_ctx.h"
+
+static char *nr_ice_media_stream_states[]={"INVALID",
+  "UNPAIRED","FROZEN","ACTIVE","COMPLETED","FAILED"
+};
+
+int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state);
+
+int nr_ice_media_stream_create(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp)
+  {
+    int r,_status;
+    nr_ice_media_stream *stream=0;
+    nr_ice_component *comp=0;
+    int i;
+
+    if(!(stream=RCALLOC(sizeof(nr_ice_media_stream))))
+      ABORT(R_NO_MEMORY);
+
+    if(!(stream->label=r_strdup(label)))
+      ABORT(R_NO_MEMORY);
+
+    stream->ctx=ctx;
+
+    STAILQ_INIT(&stream->components);
+    for(i=0;i<components;i++){
+      /* component-id must be > 0, so increment by 1 */
+      if(r=nr_ice_component_create(stream, i+1, &comp))
+        ABORT(r);
+
+    }
+
+    TAILQ_INIT(&stream->check_list);
+
+    stream->component_ct=components;
+    stream->ice_state = NR_ICE_MEDIA_STREAM_UNPAIRED;
+    *streamp=stream;
+
+    _status=0;
+  abort:
+    if(_status){
+      nr_ice_media_stream_destroy(&stream);
+    }
+    return(_status);
+  }
+
+int nr_ice_media_stream_destroy(nr_ice_media_stream **streamp)
+  {
+    nr_ice_media_stream *stream;
+    nr_ice_component *c1,*c2;
+    nr_ice_cand_pair *p1,*p2;
+    if(!streamp || !*streamp)
+      return(0);
+
+    stream=*streamp;
+    *streamp=0;
+
+    STAILQ_FOREACH_SAFE(c1, &stream->components, entry, c2){
+      STAILQ_REMOVE(&stream->components,c1,nr_ice_component_,entry);
+      nr_ice_component_destroy(&c1);
+    }
+    
+    TAILQ_FOREACH_SAFE(p1, &stream->check_list, entry, p2){
+      TAILQ_REMOVE(&stream->check_list,p1,entry);
+      nr_ice_candidate_pair_destroy(&p1);
+    }
+   
+    RFREE(stream->label);
+    
+    RFREE(stream->ufrag);
+    RFREE(stream->pwd);
+
+    if(stream->timer)
+      NR_async_timer_cancel(stream->timer);
+
+    RFREE(stream);
+
+    return(0);
+  }
+
+int nr_ice_media_stream_initialize(nr_ice_ctx *ctx, nr_ice_media_stream *stream)
+  {
+    int r,_status;
+    nr_ice_component *comp;
+
+    comp=STAILQ_FIRST(&stream->components);
+    while(comp){
+      if(r=nr_ice_component_initialize(ctx,comp))
+        ABORT(r);
+      comp=STAILQ_NEXT(comp,entry);
+    }
+    
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+#define MAX_ATTRIBUTE_SIZE 256
+
+int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attrsp, int *attrctp)
+  {
+    int attrct=0;
+    nr_ice_component *comp;
+    char **attrs=0;
+    int index=0;
+    int r,_status;
+
+    *attrctp=0;
+
+    /* First find out how many attributes we need */
+    comp=STAILQ_FIRST(&stream->components);
+    while(comp){
+      if(r=nr_ice_component_prune_candidates(stream->ctx,comp))
+        ABORT(r);
+
+      attrct+=comp->candidate_ct;
+      
+      comp=STAILQ_NEXT(comp,entry);
+    }
+
+    if(attrct < 1){
+      r_log(LOG_ICE,LOG_WARNING,"ICE-STREAM(%s): Failed to find any components for stream",stream->label);
+      ABORT(R_FAILED);
+    }
+
+    /* Make the array we'll need */
+    if(!(attrs=RCALLOC(sizeof(char *)*attrct)))
+      ABORT(R_NO_MEMORY);
+    for(index=0;index<attrct;index++){
+      if(!(attrs[index]=RMALLOC(MAX_ATTRIBUTE_SIZE)))
+        ABORT(R_NO_MEMORY);
+    }
+
+    index=0;
+    /* Now format the attributes */
+    comp=STAILQ_FIRST(&stream->components);
+    while(comp){
+      nr_ice_candidate *cand;
+
+      cand=TAILQ_FIRST(&comp->candidates);
+      while(cand){
+        assert(index < attrct);
+
+        if(r=nr_ice_format_candidate_attribute(cand, attrs[index],MAX_ATTRIBUTE_SIZE))
+          ABORT(r);
+        
+        index++;
+
+        cand=TAILQ_NEXT(cand,entry_comp);
+      }
+      comp=STAILQ_NEXT(comp,entry);
+    }
+
+    *attrsp=attrs;
+    *attrctp=attrct;
+
+    _status=0;
+  abort:
+    if(_status){
+      if(attrs){
+        for(index=0;index<attrct;index++){
+          RFREE(attrs[index]);
+        }
+        RFREE(attrs);
+      }
+    }
+    return(_status);
+  }
+
+
+/* Get a default candidate per 4.1.4 */
+int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int component, nr_ice_candidate **candp)
+  {
+    int _status;
+    nr_ice_component *comp;
+    nr_ice_candidate *cand;
+    nr_ice_candidate *best_cand = NULL;
+
+    comp=STAILQ_FIRST(&stream->components);
+    while(comp){
+      if (comp->component_id == component)
+        break;
+      
+      comp=STAILQ_NEXT(comp,entry);
+    }
+    
+    if (!comp)
+      ABORT(R_NOT_FOUND);
+
+    /* We have the component. Now find the "best" candidate, making 
+       use of the fact that more "reliable" candidate types have
+       higher numbers. So, we sort by type and then priority within
+       type
+    */
+    cand=TAILQ_FIRST(&comp->candidates);
+    while(cand){
+      if (!best_cand) {
+        best_cand = cand;
+      }
+      else {
+        if (best_cand->type < cand->type) {
+          best_cand = cand;
+        } else if (best_cand->type == cand->type) { 
+          if (best_cand->priority < cand->priority)
+            best_cand = cand;
+        }
+      }
+
+      cand=TAILQ_NEXT(cand,entry_comp);
+    }
+    
+    /* No candidates */
+    if (!best_cand)
+      ABORT(R_NOT_FOUND);
+
+    *candp = best_cand;
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+
+int nr_ice_media_stream_pair_candidates(nr_ice_peer_ctx *pctx,nr_ice_media_stream *lstream,nr_ice_media_stream *pstream)
+  {
+    int r,_status;
+    nr_ice_component *pcomp,*lcomp;
+
+    pcomp=STAILQ_FIRST(&pstream->components);
+    lcomp=STAILQ_FIRST(&lstream->components);
+    while(pcomp){
+      if(r=nr_ice_component_pair_candidates(pctx,lcomp,pcomp))
+        ABORT(r);
+
+      lcomp=STAILQ_NEXT(lcomp,entry);
+      pcomp=STAILQ_NEXT(pcomp,entry);
+    };
+
+    if (pstream->ice_state == NR_ICE_MEDIA_STREAM_UNPAIRED) {
+      r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): unfreezing stream %s",pstream->pctx->label,pstream->label);
+      pstream->ice_state = NR_ICE_MEDIA_STREAM_CHECKS_FROZEN;
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+/* S 5.8 -- run the highest priority WAITING pair or if not available
+   FROZEN pair */
+static void nr_ice_media_stream_check_timer_cb(NR_SOCKET s, int h, void *cb_arg)
+  {
+    int r,_status;
+    nr_ice_media_stream *stream=cb_arg;
+    nr_ice_cand_pair *pair;
+    int timer_val;
+
+    assert(stream->pctx->active_streams!=0);
+
+    timer_val=stream->pctx->ctx->Ta*stream->pctx->active_streams;
+
+    if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED) {
+      r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): bogus state for stream %s",stream->pctx->label,stream->label);
+    }
+    assert(stream->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED);
+    
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): check timer expired for media stream %s",stream->pctx->label,stream->label);
+    stream->timer=0;
+
+    /* Find the highest priority WAITING check and move it to RUNNING */
+    pair=TAILQ_FIRST(&stream->check_list);
+    while(pair){
+      if(pair->state==NR_ICE_PAIR_STATE_WAITING)
+        break;
+      pair=TAILQ_NEXT(pair,entry);
+    }
+
+    /* Hmmm... No WAITING. Let's look for FROZEN */
+    if(!pair){
+      pair=TAILQ_FIRST(&stream->check_list);
+
+      while(pair){
+        if(pair->state==NR_ICE_PAIR_STATE_FROZEN){
+          if(r=nr_ice_candidate_pair_unfreeze(stream->pctx,pair))
+            ABORT(r);
+          break;
+        }
+        pair=TAILQ_NEXT(pair,entry);
+      }
+    }
+
+    if(pair){
+      nr_ice_candidate_pair_start(pair->pctx,pair); /* Ignore failures */
+      NR_ASYNC_TIMER_SET(timer_val,nr_ice_media_stream_check_timer_cb,cb_arg,&stream->timer);
+    }
+    /* TODO(ekr@rtfm.com): Report on the special case where there are no checks to
+       run at all */
+    _status=0;
+  abort:
+    return;
+  }
+
+
+/* Start checks for this media stream (aka check list) */
+int nr_ice_media_stream_start_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
+  {
+    assert(stream->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FROZEN);
+    nr_ice_media_stream_set_state(stream,NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE);
+    nr_ice_media_stream_check_timer_cb(0,0,stream);
+
+    return(0);
+  }
+  
+/* Start checks for this media stream (aka check list) S 5.7 */
+int nr_ice_media_stream_unfreeze_pairs(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
+  {
+    int r,_status;
+    r_assoc *assoc=0;
+    nr_ice_cand_pair *pair=0;
+
+    /* Already seen assoc */
+    if(r=r_assoc_create(&assoc,r_assoc_crc32_hash_compute,5))
+      ABORT(r);
+
+    /* S 5.7.4. Set the highest priority pairs in each foundation to WAITING */
+    pair=TAILQ_FIRST(&stream->check_list);
+    while(pair){
+      void *v;
+      
+      if(r=r_assoc_fetch(assoc,pair->foundation,strlen(pair->foundation),&v)){
+        if(r!=R_NOT_FOUND)
+          ABORT(r);
+        if(r=nr_ice_candidate_pair_unfreeze(pctx,pair))
+          ABORT(r);
+        
+        if(r=r_assoc_insert(assoc,pair->foundation,strlen(pair->foundation),
+          0,0,0,R_ASSOC_NEW))
+          ABORT(r);
+      }
+      
+      /* Already exists... fall through */
+      pair=TAILQ_NEXT(pair,entry);
+    }
+
+    _status=0;
+  abort:
+    r_assoc_destroy(&assoc);
+    return(_status);
+  }
+
+static int nr_ice_media_stream_unfreeze_pairs_match(nr_ice_media_stream *stream, char *foundation)
+  {
+    nr_ice_cand_pair *pair;
+    int r,_status;
+    int unfroze=0;
+
+    pair=TAILQ_FIRST(&stream->check_list);
+    while(pair){
+      if(pair->state==NR_ICE_PAIR_STATE_FROZEN && 
+        !strcmp(foundation,pair->foundation)){
+        if(r=nr_ice_candidate_pair_unfreeze(stream->pctx,pair))
+          ABORT(r);
+        unfroze++;
+      }
+      pair=TAILQ_NEXT(pair,entry);
+    }
+
+    if(!unfroze)
+      return(R_NOT_FOUND);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+/* S 7.1.2.2 */
+int nr_ice_media_stream_unfreeze_pairs_foundation(nr_ice_media_stream *stream, char *foundation)
+  {
+    int r,_status;
+    nr_ice_media_stream *str;
+       nr_ice_component *comp;
+    int invalid_comps=0;
+    
+    /* 1. Unfreeze all frozen pairs with the same foundation
+       in this stream */
+    if(r=nr_ice_media_stream_unfreeze_pairs_match(stream,foundation)){
+      if(r!=R_NOT_FOUND)
+        ABORT(r);
+    }
+
+    /* 2. See if there is a pair in the valid list for every component */
+    comp=STAILQ_FIRST(&stream->components);
+    while(comp){
+      if(!comp->valid_pairs)
+        invalid_comps++;
+
+      comp=STAILQ_NEXT(comp,entry);
+    }
+    
+    /* If there is a pair in the valid list for every component... */
+    /* Now go through the check lists for the other streams */
+    str=STAILQ_FIRST(&stream->pctx->peer_streams);
+    while(str){
+      if(str!=stream){
+        switch(str->ice_state){
+          case NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE:
+            /* Unfreeze matching pairs */
+            if(r=nr_ice_media_stream_unfreeze_pairs_match(str,foundation)){
+              if(r!=R_NOT_FOUND)
+                ABORT(r);
+            }
+            break;
+          case NR_ICE_MEDIA_STREAM_CHECKS_FROZEN:
+            /* Unfreeze matching pairs if any */
+            r=nr_ice_media_stream_unfreeze_pairs_match(str,foundation);
+            if(r){
+              if(r!=R_NOT_FOUND)
+                ABORT(r);
+              
+              /* OK, no matching pairs: execute the algorithm from 5.7
+                 for this stream */
+              if(r=nr_ice_media_stream_unfreeze_pairs(str->pctx,str))
+                ABORT(r);
+            }
+            if(r=nr_ice_media_stream_start_checks(str->pctx,str))
+              ABORT(r);
+
+            break;
+          default:
+            break;
+        }
+      }
+
+      str=STAILQ_NEXT(str,entry);
+    }
+
+//    nr_ice_media_stream_dump_state(stream->pctx,stream,stderr);
+      
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+
+int nr_ice_media_stream_dump_state(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream,FILE *out)
+  {
+    nr_ice_cand_pair *pair;
+
+    //r_log(LOG_ICE,LOG_DEBUG,"MEDIA-STREAM(%s): state dump", stream->label);
+    pair=TAILQ_FIRST(&stream->check_list);
+    while(pair){
+      nr_ice_candidate_pair_dump_state(pair,out);
+      
+      pair=TAILQ_NEXT(pair,entry);
+    }
+
+    return(0);
+  }
+
+int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state)
+  {
+    // removed, per EKR:  assert(state!=str->ice_state);
+      
+    r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): stream %s state %s->%s",
+      str->pctx->label,str->label,
+      nr_ice_media_stream_states[str->ice_state],
+      nr_ice_media_stream_states[state]);
+    
+    if(str->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE)
+      str->pctx->active_streams++;
+    if(str->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE)
+      str->pctx->active_streams--;
+
+    str->ice_state=state;
+    
+    return(0);
+  }
+
+/* S OK, this component has a nominated. If every component has a nominated, 
+   the stream is ready */
+int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component)
+  {
+    int r,_status;
+    nr_ice_component *comp;
+
+    comp=STAILQ_FIRST(&stream->components);
+    while(comp){
+      if(!comp->nominated)
+        break;
+
+      comp=STAILQ_NEXT(comp,entry);
+    }
+
+    /* At least one un-nominated component */
+    if(comp)
+      goto done;
+
+    /* All done... */
+    r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/ICE-STREAM(%s): all components have nominated candidate pairs",stream->pctx->label,stream->label);
+    nr_ice_media_stream_set_state(stream,NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED);
+    
+    /* Cancel our timer */
+    if(stream->timer){
+      NR_async_timer_cancel(stream->timer);
+      stream->timer=0;
+    }
+
+    if (stream->pctx->handler) {
+      stream->pctx->handler->vtbl->stream_ready(stream->pctx->handler->obj,stream->local_stream);
+    }
+
+    /* Now tell the peer_ctx that we're done */
+    if(r=nr_ice_peer_ctx_stream_done(stream->pctx,stream))
+      ABORT(r);
+    
+  done:
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_component *component)
+  {
+    int r,_status;
+    nr_ice_cand_pair *p2;
+
+    component->state=NR_ICE_COMPONENT_FAILED;
+
+    /* at least one component failed in this media stream, so the entire
+     * media stream is marked failed */
+
+    nr_ice_media_stream_set_state(stream,NR_ICE_MEDIA_STREAM_CHECKS_FAILED);
+
+    /* OK, we need to cancel off everything on this component */
+    p2=TAILQ_FIRST(&stream->check_list);
+    while(p2){
+      if(r=nr_ice_candidate_pair_cancel(p2->pctx,p2))
+        ABORT(r);
+      
+      p2=TAILQ_NEXT(p2,entry);
+    }
+
+    /* Cancel our timer */
+    if(stream->timer){
+      NR_async_timer_cancel(stream->timer);
+      stream->timer=0;
+    }
+
+    if (stream->pctx->handler) {
+      stream->pctx->handler->vtbl->stream_failed(stream->pctx->handler->obj,stream->local_stream);
+    }
+
+    /* Now tell the peer_ctx that we're done */
+    if(r=nr_ice_peer_ctx_stream_done(stream->pctx,stream))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_media_stream_get_best_candidate(nr_ice_media_stream *str, int component, nr_ice_candidate **candp)
+  {
+    nr_ice_candidate *cand;
+    nr_ice_candidate *best_cand=0;
+    nr_ice_component *comp;
+    int r,_status;
+
+    if(r=nr_ice_media_stream_find_component(str,component,&comp))
+      ABORT(r);
+
+    cand=TAILQ_FIRST(&comp->candidates);
+    while(cand){
+      if(cand->state==NR_ICE_CAND_STATE_INITIALIZED){
+        if(!best_cand || (cand->priority>best_cand->priority))
+          best_cand=cand;
+        
+      }
+      cand=TAILQ_NEXT(cand,entry_comp);
+    }
+    
+    if(!best_cand)
+      ABORT(R_NOT_FOUND);
+
+    *candp=best_cand;
+    
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+
+/* OK, we have the stream the user created, but that reflects the base
+   ICE ctx, not the peer_ctx. So, find the related stream in the pctx,
+   and then find the component */
+int nr_ice_media_stream_find_component(nr_ice_media_stream *str, int comp_id, nr_ice_component **compp)
+  {
+    int _status;
+    nr_ice_component *comp;
+
+    comp=STAILQ_FIRST(&str->components);
+    while(comp){
+      if(comp->component_id==comp_id)
+        break;
+      
+      comp=STAILQ_NEXT(comp,entry);
+    }
+    if(!comp)
+      ABORT(R_NOT_FOUND);
+
+    *compp=comp;
+    
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+
+int nr_ice_media_stream_send(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component, UCHAR *data, int len)
+  {
+    int r,_status;
+    nr_ice_component *comp;
+
+    /* First find the peer component */
+    if(r=nr_ice_peer_ctx_find_component(pctx, str, component, &comp))
+      ABORT(r);
+
+    /* Do we have an active pair yet? We should... */
+    if(!comp->active)
+      ABORT(R_BAD_ARGS);
+
+    /* OK, write to that pair, which means:
+       1. Use the socket on our local side.
+       2. Use the address on the remote side
+    */
+    comp->keepalive_needed=0; /* Suppress keepalives */
+    if(r=nr_socket_sendto(comp->active->local->osock,data,len,0,
+      &comp->active->remote->addr))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+
+int nr_ice_media_stream_addrs(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component, nr_transport_addr *local, nr_transport_addr *remote)
+  {
+    int r,_status;
+    nr_ice_component *comp;
+
+    /* First find the peer component */
+    if(r=nr_ice_peer_ctx_find_component(pctx, str, component, &comp))
+      ABORT(r);
+
+    /* Do we have an active pair yet? We should... */
+    if(!comp->active)
+      ABORT(R_BAD_ARGS);
+
+    /* Use the socket on our local side */
+    if(r=nr_socket_getaddr(comp->active->local->osock,local))
+      ABORT(r);
+
+    /* Use the address on the remote side */
+    if(r=nr_transport_addr_copy(remote,&comp->active->remote->addr))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+
+
+int nr_ice_media_stream_finalize(nr_ice_media_stream *lstr,nr_ice_media_stream *rstr)
+  {
+    nr_ice_component *lcomp,*rcomp;
+
+    r_log(LOG_ICE,LOG_DEBUG,"Finalizing media stream %s, peer=%s",lstr->label,
+      rstr?rstr->label:"NONE");
+
+    lcomp=STAILQ_FIRST(&lstr->components);
+    if(rstr)
+      rcomp=STAILQ_FIRST(&rstr->components);
+    else
+      rcomp=0;
+
+    while(lcomp){
+      nr_ice_component_finalize(lcomp,rcomp);
+      
+      lcomp=STAILQ_NEXT(lcomp,entry);
+      if(rcomp){
+        rcomp=STAILQ_NEXT(rcomp,entry);
+      }
+    }
+
+    return(0);
+  }
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.h
@@ -0,0 +1,98 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _ice_media_stream_h
+#define _ice_media_stream_h
+#ifdef __cplusplus
+using namespace std;
+extern "C" {
+#endif /* __cplusplus */
+
+struct nr_ice_media_stream_ {
+  char *label;
+  struct nr_ice_ctx_ *ctx;
+  struct nr_ice_peer_ctx_ *pctx;
+
+  struct nr_ice_media_stream_ *local_stream; /* used when this is a peer */
+  int component_ct;
+  nr_ice_component_head components;
+
+  char *ufrag;    /* ICE username */
+  char *pwd;    /* ICE password */
+
+  int ice_state;
+
+#define NR_ICE_MEDIA_STREAM_UNPAIRED           1
+#define NR_ICE_MEDIA_STREAM_CHECKS_FROZEN      2
+#define NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE      3
+#define NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED   4
+#define NR_ICE_MEDIA_STREAM_CHECKS_FAILED      5
+
+  nr_ice_cand_pair_head check_list;
+  void *timer;  /* Check list periodic timer */
+
+//  nr_ice_cand_pair_head valid_list;
+
+  STAILQ_ENTRY(nr_ice_media_stream_) entry;
+};
+
+typedef STAILQ_HEAD(nr_ice_media_stream_head_,nr_ice_media_stream_) nr_ice_media_stream_head;
+
+int nr_ice_media_stream_create(struct nr_ice_ctx_ *ctx,char *label, int components, nr_ice_media_stream **streamp);
+int nr_ice_media_stream_destroy(nr_ice_media_stream **streamp);
+int nr_ice_media_stream_finalize(nr_ice_media_stream *lstr,nr_ice_media_stream *rstr);
+int nr_ice_media_stream_initialize(struct nr_ice_ctx_ *ctx, nr_ice_media_stream *stream);
+int nr_ice_media_stream_get_attributes(nr_ice_media_stream *stream, char ***attrsp,int *attrctp);
+int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int component, nr_ice_candidate **candp);
+int nr_ice_media_stream_pair_candidates(nr_ice_peer_ctx *pctx,nr_ice_media_stream *lstream,nr_ice_media_stream *pstream);
+int nr_ice_media_stream_start_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream);
+int nr_ice_media_stream_unfreeze_pairs(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream);
+int nr_ice_media_stream_unfreeze_pairs_foundation(nr_ice_media_stream *stream, char *foundation);
+int nr_ice_media_stream_dump_state(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream,FILE *out);
+int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component);
+int nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_component *component);
+int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state);
+int nr_ice_media_stream_get_best_candidate(nr_ice_media_stream *str, int component, nr_ice_candidate **candp);
+int nr_ice_media_stream_send(nr_ice_peer_ctx *pctx,nr_ice_media_stream *str, int component, UCHAR *data, int len);
+int nr_ice_media_stream_find_component(nr_ice_media_stream *str, int comp_id, nr_ice_component **compp);
+int nr_ice_media_stream_addrs(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component, nr_transport_addr *local, nr_transport_addr *remote);
+int
+nr_ice_peer_ctx_parse_media_stream_attribute(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *attr);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_parser.c
@@ -0,0 +1,537 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: ice_parser.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
+
+#include <csi_platform.h>
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <strings.h>
+#endif
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include "nr_api.h"
+#include "ice_ctx.h"
+#include "ice_candidate.h"
+#include "ice_reg.h"
+
+static void
+skip_whitespace(char **str)
+{
+    char *c = *str;
+    while (*c == ' ')
+        ++c;
+
+    *str = c;
+}
+
+static void
+fast_forward(char **str, int skip)
+{
+    char *c = *str;
+    while (*c != '\0' && skip-- > 0)
+        ++c;
+
+    *str = c;
+}
+
+static void
+skip_to_past_space(char **str)
+{
+    char *c = *str;
+    while (*c != ' ' && *c != '\0')
+        ++c;
+
+    *str = c;
+
+    skip_whitespace(str);
+}
+
+static int
+grab_token(char **str, char **out)
+{
+    int _status;
+    char *c = *str;
+    int len;
+    char *tmp;
+
+    while (*c != ' ' && *c != '\0')
+        ++c;
+
+    len = c - *str;
+
+    tmp = RMALLOC(len + 1);
+    if (!tmp)
+        ABORT(R_NO_MEMORY);
+
+    strncpy(tmp, *str, len);
+    tmp[len] = '\0';
+
+    *str = c;
+    *out = tmp;
+
+    _status = 0;
+abort:
+    return _status;
+}
+
+int
+nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_stream *stream,nr_ice_candidate **candp)
+{
+    int r,_status;
+    char* str = orig;
+    nr_ice_candidate *cand;
+    char *connection_address=0;
+    unsigned int port;
+    in_addr_t addr;
+    int i;
+    unsigned int component_id;
+    char *rel_addr=0;
+
+    if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
+        ABORT(R_NO_MEMORY);
+
+    if(!(cand->label=r_strdup(orig)))
+        ABORT(R_NO_MEMORY);
+
+    cand->ctx=ctx;
+    cand->isock=0;
+    cand->state=NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED;
+    cand->stream=stream;
+    skip_whitespace(&str);
+
+    /* Candidate attr */
+    if (strncasecmp(str, "candidate:", 10))
+        ABORT(R_BAD_DATA);
+
+    fast_forward(&str, 10);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    skip_whitespace(&str);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    /* Foundation */
+    if ((r=grab_token(&str, &cand->foundation)))
+        ABORT(r);
+
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    skip_whitespace(&str);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    /* component */
+    if (sscanf(str, "%u", &component_id) != 1)
+        ABORT(R_BAD_DATA);
+
+    if (component_id < 1 || component_id > 256)
+        ABORT(R_BAD_DATA);
+
+    cand->component_id = (UCHAR)component_id;
+
+    skip_to_past_space(&str);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    /* Protocol */
+    if (strncasecmp(str, "UDP", 3))
+        ABORT(R_BAD_DATA);
+
+    fast_forward(&str, 3);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    skip_whitespace(&str);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    /* priority */
+    if (sscanf(str, "%u", &cand->priority) != 1)
+        ABORT(R_BAD_DATA);
+
+    if (cand->priority < 1)
+        ABORT(R_BAD_DATA);
+
+    skip_to_past_space(&str);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    /* Peer address/port */
+    if ((r=grab_token(&str, &connection_address)))
+        ABORT(r);
+
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    addr = inet_addr(connection_address);
+    if (addr == INADDR_NONE)
+        ABORT(R_BAD_DATA);
+
+    skip_whitespace(&str);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    if (sscanf(str, "%u", &port) != 1)
+        ABORT(R_BAD_DATA);
+
+    if (port < 1 || port > 0x0FFFF)
+        ABORT(R_BAD_DATA);
+
+    /* Assume v4 for now */
+    if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,IPPROTO_UDP,&cand->addr))
+      ABORT(r);
+
+    skip_to_past_space(&str);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    /* Type */
+    if (strncasecmp("typ", str, 3))
+        ABORT(R_BAD_DATA);
+
+    fast_forward(&str, 3);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    skip_whitespace(&str);
+    if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+    assert(nr_ice_candidate_type_names[0] == 0);
+    for (i = 1; nr_ice_candidate_type_names[i]; ++i) {
+        if(!strncasecmp(nr_ice_candidate_type_names[i], str, strlen(nr_ice_candidate_type_names[i]))) {
+            cand->type=i;
+            break;
+        }
+    }
+    if (nr_ice_candidate_type_names[i] == 0)
+        ABORT(R_BAD_DATA);
+
+    fast_forward(&str, strlen(nr_ice_candidate_type_names[i]));
+
+    /* Look for the other side's raddr, rport */
+    /* raddr, rport */
+    switch (cand->type) {
+    case HOST:
+        break;
+    case SERVER_REFLEXIVE:
+    case PEER_REFLEXIVE:
+    case RELAYED:
+
+        skip_whitespace(&str);
+        if (*str == '\0')
+            ABORT(R_BAD_DATA);
+
+        if (strncasecmp("raddr", str, 5))
+            ABORT(R_BAD_DATA);
+
+        fast_forward(&str, 5);
+        if (*str == '\0')
+            ABORT(R_BAD_DATA);
+
+        skip_whitespace(&str);
+        if (*str == '\0')
+            ABORT(R_BAD_DATA);
+
+        if ((r=grab_token(&str, &rel_addr)))
+            ABORT(r);
+
+        if (*str == '\0')
+            ABORT(R_BAD_DATA);
+
+        addr = inet_addr(rel_addr);
+        if (addr == INADDR_NONE)
+            ABORT(R_BAD_DATA);
+
+        skip_whitespace(&str);
+        if (*str == '\0')
+            ABORT(R_BAD_DATA);
+
+        if (strncasecmp("rport", str, 5))
+              ABORT(R_BAD_DATA);
+
+        fast_forward(&str, 5);
+        if (*str == '\0')
+            ABORT(R_BAD_DATA);
+
+        skip_whitespace(&str);
+        if (*str == '\0')
+            ABORT(R_BAD_DATA);
+
+        if (sscanf(str, "%u", &port) != 1)
+            ABORT(R_BAD_DATA);
+
+        if (port < 1 || port > 0x0FFFF)
+            ABORT(R_BAD_DATA);
+
+        /* Assume v4 for now */
+        if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,IPPROTO_UDP,&cand->base))
+          ABORT(r);
+
+        skip_to_past_space(&str);
+        /* it's expected to be at EOD at this point */
+
+        break;
+    default:
+        ABORT(R_INTERNAL);
+        break;
+    }
+
+    skip_whitespace(&str);
+
+    /* This used to be an assert, but we don't want to exit on invalid
+       remote data */
+    if (strlen(str) != 0) {
+      ABORT(R_BAD_DATA);
+    }
+      
+    *candp=cand;
+
+    _status=0;
+  abort:
+    /* TODO(ekr@rtfm.com): Fix memory leak if we have a parse error */
+    if (_status)
+        r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Error parsing attribute: %s",ctx->label,orig);
+
+    RFREE(connection_address);
+    RFREE(rel_addr);
+    return(_status);
+}
+
+
+int
+nr_ice_peer_ctx_parse_media_stream_attribute(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *attr)
+{
+    int r,_status;
+    char *orig = 0;
+    char *str;
+
+    orig = str = attr;
+
+    if (!strncasecmp(str, "ice-ufrag:", 10)) {
+      fast_forward(&str, 10);
+      if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+      skip_whitespace(&str);
+      if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+      if ((r=grab_token(&str, &stream->ufrag)))
+        ABORT(r);
+    }
+    else if (!strncasecmp(str, "ice-pwd:", 8)) {
+      fast_forward(&str, 8);
+      if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+      skip_whitespace(&str);
+      if (*str == '\0')
+        ABORT(R_BAD_DATA);
+
+      if ((r=grab_token(&str, &stream->pwd)))
+        ABORT(r);
+    }
+    else {
+      ABORT(R_BAD_DATA);
+    }
+
+    skip_whitespace(&str);
+    /* it's expected to be at EOD at this point */
+
+    assert(strlen(str) == 0);
+
+    _status=0;
+  abort:
+    if (_status) {
+      if (orig)
+        r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Error parsing attribute: %s",pctx->label,orig);
+    }
+
+    return(_status);
+}
+
+int
+nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx *pctx, char **attrs, int attr_ct)
+{
+    int r,_status;
+    int i;
+    char *orig = 0;
+    char *str;
+    char *component_id = 0;
+    char *connection_address = 0;
+    unsigned int port;
+    in_addr_t addr;
+    char *ice_option_tag = 0;
+    
+    for(i=0;i<attr_ct;i++){
+        orig = str = attrs[i];
+
+        component_id = 0;
+        connection_address = 0;
+        ice_option_tag = 0;
+
+        if (!strncasecmp(str, "remote-candidates:", 18)) {
+            fast_forward(&str, 18);
+            skip_whitespace(&str);
+
+            while (*str != '\0') {
+                if ((r=grab_token(&str, &component_id)))
+                    ABORT(r);
+
+                if (*str == '\0')
+                    ABORT(R_BAD_DATA);
+
+                skip_whitespace(&str);
+                if (*str == '\0')
+                    ABORT(R_BAD_DATA);
+
+                if ((r=grab_token(&str, &connection_address)))
+                    ABORT(r);
+
+                if (*str == '\0')
+                    ABORT(R_BAD_DATA);
+
+                addr = inet_addr(connection_address);
+                if (addr == INADDR_NONE)
+                    ABORT(R_BAD_DATA);
+
+                skip_whitespace(&str);
+                if (*str == '\0')
+                    ABORT(R_BAD_DATA);
+
+                if (sscanf(str, "%u", &port) != 1)
+                    ABORT(R_BAD_DATA);
+
+                if (port < 1 || port > 0x0FFFF)
+                    ABORT(R_BAD_DATA);
+
+                skip_to_past_space(&str);
+
+#if 0
+                /* TODO: !nn! just drop on the floor for now, later put somewhere */
+                /* Assume v4 for now */
+                if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,IPPROTO_UDP,&candidate->base))
+                  ABORT(r);
+
+                TAILQ_INSERT_TAIL(head, elm, field);
+#endif
+
+                component_id = 0;  /* prevent free */
+                RFREE(connection_address);
+                connection_address = 0;  /* prevent free */
+            }
+        }
+        else if (!strncasecmp(str, "ice-lite", 8)) {
+            pctx->peer_lite = 1;
+
+            fast_forward(&str, 8);
+        }
+        else if (!strncasecmp(str, "ice-mismatch", 12)) {
+            pctx->peer_ice_mismatch = 1;
+
+            fast_forward(&str, 12);
+        }
+        else if (!strncasecmp(str, "ice-ufrag:", 10)) {
+            fast_forward(&str, 10);
+            if (*str == '\0')
+                ABORT(R_BAD_DATA);
+
+            skip_whitespace(&str);
+            if (*str == '\0')
+                ABORT(R_BAD_DATA);
+
+            if ((r=grab_token(&str, &pctx->peer_ufrag)))
+                ABORT(r);
+        }
+        else if (!strncasecmp(str, "ice-pwd:", 8)) {
+            fast_forward(&str, 8);
+            if (*str == '\0')
+                ABORT(R_BAD_DATA);
+
+            skip_whitespace(&str);
+            if (*str == '\0')
+                ABORT(R_BAD_DATA);
+
+            if ((r=grab_token(&str, &pctx->peer_pwd)))
+                ABORT(r);
+        }
+        else if (!strncasecmp(str, "ice-options:", 12)) {
+            fast_forward(&str, 12);
+            skip_whitespace(&str);
+
+            while (*str != '\0') {
+                if ((r=grab_token(&str, &ice_option_tag)))
+                    ABORT(r);
+
+                skip_whitespace(&str);
+
+#if 0
+//TODO: !nn! for now, just drop on the floor, later put somewhere
+#endif
+                ice_option_tag = 0;  /* prevent free */
+            }
+        }
+        else {
+            ABORT(R_BAD_DATA);
+        }
+
+        skip_whitespace(&str);
+        /* it's expected to be at EOD at this point */
+
+        assert(strlen(str) == 0);
+    }
+
+    _status=0;
+  abort:
+    if (_status) {
+      if (orig)
+        r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Error parsing attribute: %s",pctx->label,orig);
+    }
+
+    RFREE(connection_address);
+    RFREE(component_id);
+    RFREE(ice_option_tag);
+    return(_status);
+}
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.c
@@ -0,0 +1,519 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: ice_peer_ctx.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
+
+#include <string.h>
+#include <assert.h>
+#include <nr_api.h>
+#include "ice_ctx.h"
+#include "ice_peer_ctx.h"
+#include "nr_crypto.h"
+#include "async_timer.h"
+
+static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg);
+static int nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct);
+static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate);
+
+int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp)
+  {
+    int r,_status;
+    nr_ice_peer_ctx *pctx=0;
+
+    if(!(pctx=RCALLOC(sizeof(nr_ice_peer_ctx))))
+      ABORT(R_NO_MEMORY);
+
+    if(!(pctx->label=r_strdup(label)))
+      ABORT(R_NO_MEMORY);
+
+    pctx->ctx=ctx;
+    pctx->handler=handler;
+
+    /* Decide controlling vs. controlled */
+    if(ctx->flags & NR_ICE_CTX_FLAGS_LITE){
+      if(pctx->peer_lite){
+        r_log(LOG_ICE,LOG_ERR,"Both sides are ICE-Lite");
+        ABORT(R_BAD_DATA);
+      }
+        
+      pctx->controlling=0;
+    }
+    else{
+      if(pctx->peer_lite || (ctx->flags & NR_ICE_CTX_FLAGS_OFFERER))
+        pctx->controlling=1;
+      else if(ctx->flags & NR_ICE_CTX_FLAGS_ANSWERER)
+        pctx->controlling=0;
+    }
+    if(r=nr_crypto_random_bytes((UCHAR *)&pctx->tiebreaker,8))
+      ABORT(r);
+    
+    STAILQ_INIT(&pctx->peer_streams);
+
+    STAILQ_INSERT_TAIL(&ctx->peers,pctx,entry);
+
+    *pctxp=pctx;
+
+    _status = 0;
+  abort:
+    if(_status){
+      nr_ice_peer_ctx_destroy_cb(0,0,pctx);
+    }
+    return(_status);
+  }
+
+
+
+int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct)
+  {
+    nr_ice_media_stream *pstream=0;
+    nr_ice_component *comp,*comp2;
+    int r,_status;
+
+    /*
+      Note: use component_ct from our own stream since components other
+      than this offered by the other side are unusable */
+    if(r=nr_ice_media_stream_create(pctx->ctx,stream->label,stream->component_ct,&pstream))
+      ABORT(r);
+
+    /* Match up the local and remote components */
+    comp=STAILQ_FIRST(&stream->components);
+    comp2=STAILQ_FIRST(&pstream->components);
+    while(comp){
+      comp2->local_component=comp;
+
+      comp=STAILQ_NEXT(comp,entry);
+      comp2=STAILQ_NEXT(comp2,entry);
+    }
+
+    pstream->local_stream=stream;
+    pstream->pctx=pctx;
+
+    if (r=nr_ice_peer_ctx_parse_stream_attributes_int(pctx,stream,pstream,attrs,attr_ct))
+      ABORT(r);
+
+
+    STAILQ_INSERT_TAIL(&pctx->peer_streams,pstream,entry);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+static int nr_ice_peer_ctx_parse_stream_attributes_int(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream *pstream, char **attrs, int attr_ct)
+  {
+    int r;
+    int i;
+
+    for(i=0;i<attr_ct;i++){
+      if(!strncmp(attrs[i],"ice-",4)){
+        if(r=nr_ice_peer_ctx_parse_media_stream_attribute(pctx,pstream,attrs[i])) {
+          r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified bogus ICE attribute",pctx->ctx->label,pctx->label);
+          continue;
+        }
+      }
+      else if (!strncmp(attrs[i],"candidate",9)){
+        if(r=nr_ice_ctx_parse_candidate(pctx,pstream,attrs[i])) {
+          r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified bogus candidate",pctx->ctx->label,pctx->label);
+          continue;
+        }
+      }
+      else {
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified bogus attribute",pctx->ctx->label,pctx->label);
+      }
+    }
+
+    /* Doesn't fail because we just skip errors */
+    return(0);
+  }
+
+static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *pstream, char *candidate)
+  {
+    nr_ice_candidate *cand=0;
+    nr_ice_component *comp;
+    int j;
+    int r, _status;
+
+    if(r=nr_ice_peer_candidate_from_attribute(pctx->ctx,candidate,pstream,&cand))
+      ABORT(r);
+    if(cand->component_id-1>=pstream->component_ct){
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) specified too many components",pctx->ctx->label,pctx->label);
+      ABORT(R_BAD_DATA);
+    }
+
+    /* Not the fastest way to find a component, but it's what we got */
+    j=1;
+    for(comp=STAILQ_FIRST(&pstream->components);comp;comp=STAILQ_NEXT(comp,entry)){
+      if(j==cand->component_id)
+        break;
+
+      j++;
+    }
+
+    if(!comp){
+      r_log(LOG_ICE,LOG_ERR,"Peer answered with more components than we offered");
+      ABORT(R_BAD_DATA);
+    }
+
+    cand->component=comp;
+
+    TAILQ_INSERT_TAIL(&comp->candidates,cand,entry_comp);
+
+    _status=0;
+ abort:
+    if (_status) {
+      nr_ice_candidate_destroy(&cand);
+    }
+    return(_status);
+  }
+
+
+
+int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *candidate)
+  {
+    /* First need to find the stream. Because we don't have forward pointers,
+       iterate through all the peer streams to find one that matches us */
+    nr_ice_media_stream *pstream;
+    int r,_status;
+    int needs_pairing = 0;
+
+    pstream=STAILQ_FIRST(&pctx->peer_streams);
+    while(pstream) {
+      if (pstream->local_stream == stream)
+        break;
+      
+      pstream = STAILQ_NEXT(pstream, entry);
+    }
+    if (!pstream) {
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) has no stream matching stream %s",pctx->ctx->label,pctx->label,stream->label);
+      ABORT(R_NOT_FOUND);
+    }
+
+    switch(pstream->ice_state) {
+      case NR_ICE_MEDIA_STREAM_UNPAIRED:
+        break;
+      case NR_ICE_MEDIA_STREAM_CHECKS_FROZEN:
+      case NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE:
+        needs_pairing = 1;
+        break;
+      default:
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) tried to trickle ICE in inappropriate state %d",pctx->ctx->label,pctx->label,stream->label,pstream->ice_state);
+        ABORT(R_ALREADY);
+        break;
+    }
+
+    if(r=nr_ice_ctx_parse_candidate(pctx,pstream,candidate)){
+      ABORT(r);
+    }
+
+    /* If ICE is running (i.e., we are in FROZEN or ACTIVE states)
+       then we need to pair this new candidate. For now we
+       just re-pair the stream which is inefficient but still
+       fine because we suppress duplicate pairing */
+    if (needs_pairing) {
+      if(r=nr_ice_media_stream_pair_candidates(pctx, stream, pstream)) {
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s), stream(%s) failed to pair trickle ICE candidates",pctx->ctx->label,pctx->label,stream->label);
+        ABORT(r);
+      }
+    }
+
+    _status =0;
+ abort:
+    return(_status);
+
+  }
+
+
+int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx)
+  {
+    nr_ice_media_stream *stream;
+    int r,_status;
+
+    if(STAILQ_EMPTY(&pctx->peer_streams)) {
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) received no media stream attribributes",pctx->ctx->label,pctx->label);
+        ABORT(R_FAILED);
+    }
+
+    stream=STAILQ_FIRST(&pctx->peer_streams);
+    while(stream){
+      if(r=nr_ice_media_stream_pair_candidates(pctx, stream->local_stream, 
+        stream))
+        ABORT(r);
+
+      stream=STAILQ_NEXT(stream,entry);
+    }   
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+static void nr_ice_peer_ctx_destroy_cb(NR_SOCKET s, int how, void *cb_arg)
+  {
+    nr_ice_peer_ctx *pctx=cb_arg;
+    nr_ice_media_stream *str1,*str2;
+
+    RFREE(pctx->label);
+    RFREE(pctx->peer_ufrag);
+    RFREE(pctx->peer_pwd);
+    
+    STAILQ_FOREACH_SAFE(str1, &pctx->peer_streams, entry, str2){
+      STAILQ_REMOVE(&pctx->peer_streams,str1,nr_ice_media_stream_,entry);
+      nr_ice_media_stream_destroy(&str1);
+    }
+
+    RFREE(pctx);
+  }
+
+int nr_ice_peer_ctx_destroy(nr_ice_peer_ctx **pctxp)
+  {
+
+    if(!pctxp || !*pctxp)
+      return(0);
+
+    /* Stop calling the handler */
+    (*pctxp)->handler = 0;
+
+    NR_ASYNC_SCHEDULE(nr_ice_peer_ctx_destroy_cb,*pctxp);
+
+    *pctxp=0;
+
+    return(0);
+  }
+
+
+/* Start the checks for the first media stream (S 5.7)
+   The rest remain FROZEN */
+int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx)
+  {
+    return nr_ice_peer_ctx_start_checks2(pctx, 0);
+  }
+
+/* Start checks for some media stream.
+
+   If allow_non_first == 0, then we only look at the first stream,
+   which is 5245-complaint.
+
+   If allow_non_first == 1 then we find the first non-empty stream
+   This is not compliant with RFC 5245 but is necessary to make trickle ICE
+   work plausibly
+*/
+int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first)
+  {
+    int r,_status;
+    nr_ice_media_stream *stream;
+
+    stream=STAILQ_FIRST(&pctx->peer_streams);
+    if(!stream)
+      ABORT(R_FAILED);
+
+    while (stream) {
+      if(!TAILQ_EMPTY(&stream->check_list))
+        break;
+
+      if(!allow_non_first){
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) first stream has empty check list",pctx->ctx->label,pctx->label);
+        ABORT(R_FAILED);
+      }
+
+      stream=STAILQ_NEXT(stream, entry);
+    }
+
+    if (!stream) {
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) no streams with non-empty check lists",pctx->ctx->label,pctx->label);
+      ABORT(R_NOT_FOUND);
+    }
+
+    if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN) {
+      if(r=nr_ice_media_stream_unfreeze_pairs(pctx,stream))
+        ABORT(r);
+      if(r=nr_ice_media_stream_start_checks(pctx,stream))
+        ABORT(r);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+#ifndef NDEBUG
+int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out)
+  {
+    int r,_status;
+    nr_ice_media_stream *stream;
+
+    fprintf(out,"PEER %s STATE DUMP\n",pctx->label);
+    fprintf(out,"==========================================\n");
+    stream=STAILQ_FIRST(&pctx->peer_streams);
+    while(stream){
+      if(r=nr_ice_media_stream_dump_state(pctx,stream,out))
+        ABORT(r);
+
+      stream=STAILQ_NEXT(stream,entry);
+    }
+    fprintf(out,"==========================================\n");
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+#endif
+
+static void nr_ice_peer_ctx_fire_done(NR_SOCKET s, int how, void *cb_arg)
+  {
+    nr_ice_peer_ctx *pctx=cb_arg;
+
+    /* Fire the handler callback to say we're done */
+    if (pctx->handler) {
+      pctx->handler->vtbl->ice_completed(pctx->handler->obj, pctx);
+    }
+  }
+
+
+/* OK, a stream just went ready. Examine all the streams to see if we're
+   maybe miraculously done */
+int nr_ice_peer_ctx_stream_done(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
+  {
+    int _status;
+    nr_ice_media_stream *str;
+    int failed=0;
+    int succeeded=0;
+
+    str=STAILQ_FIRST(&pctx->peer_streams);
+    while(str){
+      if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED){
+        succeeded++;
+      }
+      else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED){
+        failed++;
+      }
+      else{
+        break;
+      }
+      str=STAILQ_NEXT(str,entry);
+    }
+ 
+    if(str)
+      goto done;  /* Something isn't done */
+
+    /* OK, we're finished, one way or another */
+    r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): all checks completed success=%d fail=%d",pctx->label,succeeded,failed);
+    
+    /* Schedule a done notification
+       IMPORTANT: This is done in a callback because we expect destructors
+       of various kinds to be fired from here */
+
+    NR_ASYNC_SCHEDULE(nr_ice_peer_ctx_fire_done,pctx);
+
+  done:
+    _status=0;
+//  abort:
+    return(_status);
+  }
+
+
+/* Given a component in the main ICE ctx, find the relevant component in
+   the peer_ctx */
+int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp)
+  {
+    nr_ice_media_stream *pstr;
+    int r,_status;
+
+    pstr=STAILQ_FIRST(&pctx->peer_streams);
+    while(pstr){
+      if(pstr->local_stream==str)
+        break;
+
+      pstr=STAILQ_NEXT(pstr,entry);
+    }
+    if(!pstr)
+      ABORT(R_BAD_ARGS);
+
+    if(r=nr_ice_media_stream_find_component(pstr,component_id,compp))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+/* 
+   This packet may be for us.
+
+   1. Find the matching peer component 
+   2. Examine the packet source address to see if it matches
+   one of the peer candidates. 
+   3. Fire the relevant callback handler if there is a match
+   
+   Return 0 if match, R_REJECTED if no match, other errors 
+   if we can't even find the component or something like that.
+*/
+
+int nr_ice_peer_ctx_deliver_packet_maybe(nr_ice_peer_ctx *pctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len)
+  {
+    nr_ice_component *peer_comp;
+    nr_ice_candidate *cand;
+    int r,_status;
+
+    if(r=nr_ice_peer_ctx_find_component(pctx, comp->stream, comp->component_id,
+      &peer_comp))
+      ABORT(r);
+
+    /* OK, we've found the component, now look for matches */
+    cand=TAILQ_FIRST(&peer_comp->candidates);
+    while(cand){
+      if(!nr_transport_addr_cmp(source_addr,&cand->addr,
+        NR_TRANSPORT_ADDR_CMP_MODE_ALL))
+        break;
+
+      cand=TAILQ_NEXT(cand,entry_comp);
+    }
+
+    if(!cand)
+      ABORT(R_REJECTED);
+
+    /* OK, there's a match. Call the handler */
+
+    if (pctx->handler) {
+      r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s): Delivering data", pctx->label);
+
+      pctx->handler->vtbl->msg_recvd(pctx->handler->obj,
+        pctx,comp->stream,comp->component_id,data,len);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.h
@@ -0,0 +1,82 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _ice_peer_ctx_h
+#define _ice_peer_ctx_h
+#ifdef __cplusplus
+using namespace std;
+extern "C" {
+#endif /* __cplusplus */
+
+struct nr_ice_peer_ctx_ {
+  char *label;
+  nr_ice_ctx *ctx;
+  nr_ice_handler *handler;
+
+  UCHAR controlling; /* 1 for controlling, 0 for controlled */
+  UINT8 tiebreaker;
+
+  char *peer_ufrag;
+  char *peer_pwd;
+  int peer_lite;
+  int peer_ice_mismatch;
+
+  nr_ice_media_stream_head peer_streams;
+  int active_streams;
+  int waiting_pairs;
+
+  STAILQ_ENTRY(nr_ice_peer_ctx_) entry;
+};
+
+typedef STAILQ_HEAD(nr_ice_peer_ctx_head_, nr_ice_peer_ctx_) nr_ice_peer_ctx_head;
+
+int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp);
+int nr_ice_peer_ctx_destroy(nr_ice_peer_ctx **pctxp);
+int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct);
+int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *cand);
+
+int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx);
+int nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx *pctx, char **attrs, int attr_ct);
+int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx);
+int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first);
+int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out);
+int nr_ice_peer_ctx_log_state(nr_ice_peer_ctx *pctx);
+int nr_ice_peer_ctx_stream_done(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream);
+int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp);
+int nr_ice_peer_ctx_deliver_packet_maybe(nr_ice_peer_ctx *pctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_reg.h
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _ice_reg_h
+#define _ice_reg_h
+#ifdef __cplusplus
+using namespace std;
+extern "C" {
+#endif /* __cplusplus */
+
+#define NR_ICE_REG_PREF_TYPE_HOST       "ice.pref.type.host"
+#define NR_ICE_REG_PREF_TYPE_RELAYED    "ice.pref.type.relayed"
+#define NR_ICE_REG_PREF_TYPE_SRV_RFLX   "ice.pref.type.srv_rflx"
+#define NR_ICE_REG_PREF_TYPE_PEER_RFLX  "ice.pref.type.peer_rflx"
+
+#define NR_ICE_REG_PREF_INTERFACE_PRFX      "ice.pref.interface"
+#define NR_ICE_REG_SUPPRESS_INTERFACE_PRFX  "ice.suppress.interface"
+
+#define NR_ICE_REG_STUN_SRV_PRFX        "ice.stun.server"
+#define NR_ICE_REG_STUN_SRV_ADDR        "addr"
+#define NR_ICE_REG_STUN_SRV_PORT        "port"
+
+#define NR_ICE_REG_TURN_SRV_PRFX        "ice.turn.server"
+#define NR_ICE_REG_TURN_SRV_ADDR        "addr"
+#define NR_ICE_REG_TURN_SRV_PORT        "port"
+#define NR_ICE_REG_TURN_SRV_BANDWIDTH   "bandwidth"
+#define NR_ICE_REG_TURN_SRV_LIFETIME    "lifetime"
+#define NR_ICE_REG_TURN_SRV_USERNAME    "username"
+#define NR_ICE_REG_TURN_SRV_PASSWORD    "password"
+
+#define NR_ICE_REG_KEEPALIVE_TIMER      "ice.keepalive_timer"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_socket.c
@@ -0,0 +1,321 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: ice_socket.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
+
+#include <assert.h>
+#include "nr_api.h"
+#include "ice_ctx.h"
+#include "stun.h"
+
+    
+static void nr_ice_socket_readable_cb(NR_SOCKET s, int how, void *cb_arg)
+  {
+    int r;
+    nr_ice_stun_ctx *sc1,*sc2;
+    nr_ice_socket *sock=cb_arg;
+    UCHAR buf[8192];
+    char string[256];
+    nr_transport_addr addr;
+    int len;
+    size_t len_s;
+    int is_stun;
+    int is_req;
+    int is_ind;
+    nr_socket *stun_srv_sock=sock->sock;
+
+    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Socket ready to read",sock->ctx->label);
+    
+    /* Re-arm first! */
+    NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg);
+
+    if(r=nr_socket_recvfrom(sock->sock,buf,sizeof(buf),&len_s,0,&addr)){
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error reading from socket",sock->ctx->label);
+      return;
+    }
+
+    /* Deal with the fact that sizeof(int) and sizeof(size_t) may not
+       be the same */
+    if (len_s > (size_t)INT_MAX)
+      return;
+
+    len = (int)len_s;
+
+#ifdef USE_TURN
+  re_process:
+#endif /* USE_TURN */
+    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Read %d bytes",sock->ctx->label,len);
+
+    /* First question: is this STUN or not? */
+    is_stun=nr_is_stun_message(buf,len);
+
+    if(is_stun){
+      snprintf(string, sizeof(string)-1, "ICE(%s): Message is STUN",sock->ctx->label);
+      r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)buf, len);
+
+      is_req=nr_is_stun_request_message(buf,len);
+      is_ind=is_req?0:nr_is_stun_indication_message(buf,len);
+
+      /* We need to offer it to all of our stun contexts
+         to see who bites */
+      sc1=TAILQ_FIRST(&sock->stun_ctxs);
+      while(sc1){
+        sc2=TAILQ_NEXT(sc1,entry);
+
+        r=-1;
+        switch(sc1->type){
+          /* This has been deleted, prune... */
+          case NR_ICE_STUN_NONE:
+            TAILQ_REMOVE(&sock->stun_ctxs,sc1,entry);
+            RFREE(sc1);
+            break;
+
+          case NR_ICE_STUN_CLIENT:
+            if(!(is_req||is_ind)){
+                r=nr_stun_client_process_response(sc1->u.client,buf,len,&addr);
+            }
+            break;
+
+          case NR_ICE_STUN_SERVER:
+            if(is_req){
+              r=nr_stun_server_process_request(sc1->u.server,stun_srv_sock,(char *)buf,len,&addr,NR_STUN_AUTH_RULE_SHORT_TERM);
+            }
+            break;
+
+#ifdef USE_TURN
+          case NR_ICE_TURN_CLIENT:
+            /* data indications are ok, so don't ignore those */
+            if(!is_req){
+              if(!is_ind)
+                r=nr_turn_client_process_response(sc1->u.turn_client,buf,len,&addr);
+              else{
+                /* This is a bit of a hack. If it's a data indication, strip
+                   off the TURN framing and re-enter. We don't care about
+                   other kinds of indication */
+                nr_transport_addr n_addr;
+                size_t n_len;
+                
+                r=nr_turn_client_rewrite_indication_data(buf,len,&n_len,&n_addr);
+                if(!r){
+                  r_log(LOG_ICE,LOG_DEBUG,"Unwrapped a data indication.");
+                  len=n_len;
+                  nr_transport_addr_copy(&addr,&n_addr);
+                  stun_srv_sock=sc1->u.turn_client->wrapping_sock;
+                  goto re_process;
+                }
+              }
+            }
+            break;
+#endif /* USE_TURN */
+
+          default:
+            assert(0); /* Can't happen */
+            return;
+        }
+        if(!r){
+          break;
+        }        
+
+        sc1=sc2;
+      }
+      if(!sc1){
+        if (nr_ice_ctx_is_known_id(sock->ctx,((nr_stun_message_header*)buf)->id.octet))
+            r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Message is a retransmit",sock->ctx->label);
+        else
+            r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Message does not correspond to any registered stun ctx",sock->ctx->label);
+      }
+    }
+    else{
+      r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Message is not STUN",sock->ctx->label);
+      
+      nr_ice_ctx_deliver_packet(sock->ctx, sock->component, &addr, buf, len);
+    }
+
+    return;
+  }
+
+int nr_ice_socket_create(nr_ice_ctx *ctx,nr_ice_component *comp, nr_socket *nsock, nr_ice_socket **sockp)
+  {
+    nr_ice_socket *sock=0;
+    NR_SOCKET fd;
+    int _status;
+
+    if(!(sock=RCALLOC(sizeof(nr_ice_socket))))
+      ABORT(R_NO_MEMORY);
+
+    sock->sock=nsock;
+    sock->ctx=ctx;
+    sock->component=comp;
+
+    TAILQ_INIT(&sock->candidates);
+    TAILQ_INIT(&sock->stun_ctxs);
+    
+    nr_socket_getfd(nsock,&fd);
+    NR_ASYNC_WAIT(fd,NR_ASYNC_WAIT_READ,nr_ice_socket_readable_cb,sock);
+
+    *sockp=sock;
+
+    _status=0;
+  abort:
+    if(_status) RFREE(sock);
+    return(_status);
+  }
+
+
+int nr_ice_socket_destroy(nr_ice_socket **isockp)
+  {
+    nr_ice_stun_ctx *s1,*s2;
+    nr_ice_socket *isock;
+    
+    if(!isockp || !*isockp)
+      return(0);
+    
+    isock=*isockp;
+    *isockp=0;
+
+    /* Close the socket */
+    nr_ice_socket_close(isock);
+    
+    /* The STUN server */
+    nr_stun_server_ctx_destroy(&isock->stun_server);
+
+    /* Now clean up the STUN ctxs */
+    TAILQ_FOREACH_SAFE(s1, &isock->stun_ctxs, entry, s2){
+      TAILQ_REMOVE(&isock->stun_ctxs, s1, entry);
+      RFREE(s1);
+    }
+
+    RFREE(isock);
+    
+    return(0);
+  }
+
+int nr_ice_socket_close(nr_ice_socket *isock)
+  {
+#ifdef NR_SOCKET_IS_VOID_PTR
+    NR_SOCKET fd=NULL;
+    NR_SOCKET no_socket = NULL;
+#else
+    NR_SOCKET fd=-1;
+    NR_SOCKET no_socket = -1;
+#endif
+
+    if (!isock||!isock->sock)
+      return(0);
+
+    nr_socket_getfd(isock->sock,&fd);
+    assert(isock->sock!=0);
+    if(fd != no_socket){
+      NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_READ);
+      NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_WRITE);
+      nr_socket_destroy(&isock->sock);
+    }
+    
+    return(0);
+  }
+
+int nr_ice_socket_register_stun_client(nr_ice_socket *sock, nr_stun_client_ctx *srv,void **handle)
+  {
+    nr_ice_stun_ctx *sc=0;
+    int _status;
+
+    if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx))))
+      ABORT(R_NO_MEMORY);
+
+    sc->type=NR_ICE_STUN_CLIENT;
+    sc->u.client=srv;
+
+    TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry);
+    
+    *handle=sc;
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_socket_register_stun_server(nr_ice_socket *sock, nr_stun_server_ctx *srv,void **handle)
+  {
+    nr_ice_stun_ctx *sc=0;
+    int _status;
+
+    if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx))))
+      ABORT(R_NO_MEMORY);
+
+    sc->type=NR_ICE_STUN_SERVER;
+    sc->u.server=srv;
+
+    TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry);
+
+    *handle=sc;
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ice_socket_register_turn_client(nr_ice_socket *sock, nr_turn_client_ctx *srv,void **handle)
+  {
+    nr_ice_stun_ctx *sc=0;
+    int _status;
+
+    if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx))))
+      ABORT(R_NO_MEMORY);
+
+    sc->type=NR_ICE_TURN_CLIENT;
+    sc->u.turn_client=srv;
+
+    TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry);
+
+    *handle=sc;
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+/* Just mark it deregistered. Don't delete it now because it's not safe
+   in the CB, which is where this is likely to be called */
+int nr_ice_socket_deregister(nr_ice_socket *sock, void *handle)
+  {
+    nr_ice_stun_ctx *sc=handle;
+
+    if(!sc)
+      return(0);
+    
+    sc->type=NR_ICE_STUN_NONE;
+
+    return(0);
+  }
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_socket.h
@@ -0,0 +1,89 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _ice_socket_h
+#define _ice_socket_h
+#ifdef __cplusplus
+using namespace std;
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct nr_ice_stun_ctx_ {
+  int type;
+#define NR_ICE_STUN_NONE    0 /* Deregistered */
+#define NR_ICE_STUN_CLIENT  1
+#define NR_ICE_STUN_SERVER  2
+#define NR_ICE_TURN_CLIENT  3
+  
+  union {
+    nr_stun_client_ctx *client;
+    nr_stun_server_ctx *server;
+    nr_turn_client_ctx *turn_client;
+  } u;
+
+  TAILQ_ENTRY(nr_ice_stun_ctx_) entry;
+} nr_ice_stun_ctx;
+
+
+
+typedef struct nr_ice_socket_ {
+  nr_socket *sock;
+  nr_ice_ctx *ctx;
+  
+  nr_ice_candidate_head candidates;
+  nr_ice_component *component;
+
+  TAILQ_HEAD(nr_ice_stun_ctx_head_,nr_ice_stun_ctx_) stun_ctxs;
+
+  nr_stun_server_ctx *stun_server;
+  void *stun_server_handle;
+
+  STAILQ_ENTRY(nr_ice_socket_) entry;
+} nr_ice_socket;
+
+typedef STAILQ_HEAD(nr_ice_socket_head_,nr_ice_socket_) nr_ice_socket_head;
+
+int nr_ice_socket_create(struct nr_ice_ctx_ *ctx, struct nr_ice_component_ *comp, nr_socket *nsock, nr_ice_socket **sockp);
+int nr_ice_socket_destroy(nr_ice_socket **isock);
+int nr_ice_socket_close(nr_ice_socket *isock);
+int nr_ice_socket_register_stun_client(nr_ice_socket *sock, nr_stun_client_ctx *srv,void **handle);
+int nr_ice_socket_register_stun_server(nr_ice_socket *sock, nr_stun_server_ctx *srv,void **handle);
+int nr_ice_socket_register_turn_client(nr_ice_socket *sock, nr_turn_client_ctx *srv,void **handle);
+int nr_ice_socket_deregister(nr_ice_socket *sock, void *handle);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/net/nr_socket.c
@@ -0,0 +1,102 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: nr_socket.c,v 1.2 2008/04/28 17:59:02 ekr Exp $";
+
+#include <nr_api.h>
+#include "nr_socket.h"
+
+int nr_socket_create_int(void *obj, nr_socket_vtbl *vtbl, nr_socket **sockp)
+  {
+    int _status;
+    nr_socket *sock=0;
+
+    if(!(sock=RCALLOC(sizeof(nr_socket))))
+      ABORT(R_NO_MEMORY);
+
+    sock->obj=obj;
+    sock->vtbl=vtbl;
+
+    *sockp=sock;
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_socket_destroy(nr_socket **sockp)
+  {
+    nr_socket *sock;
+
+    if(!sockp || !*sockp)
+      return(0);
+
+    sock=*sockp;
+    *sockp=0;
+
+    sock->vtbl->destroy(&sock->obj);
+
+    RFREE(sock);
+    
+    return(0);
+  }
+
+int nr_socket_sendto(nr_socket *sock,const void *msg, size_t len, int flags,
+  nr_transport_addr *addr)
+  {
+    return sock->vtbl->ssendto(sock->obj,msg,len,flags,addr);
+  }
+
+
+int nr_socket_recvfrom(nr_socket *sock,void * restrict buf, size_t maxlen,
+  size_t *len, int flags, nr_transport_addr *addr)
+  {
+    return sock->vtbl->srecvfrom(sock->obj, buf, maxlen, len, flags, addr);
+  }
+
+int nr_socket_getfd(nr_socket *sock, NR_SOCKET *fd)
+  {
+    return sock->vtbl->getfd(sock->obj, fd);
+  }
+  
+int nr_socket_getaddr(nr_socket *sock, nr_transport_addr *addrp)
+  {
+    return sock->vtbl->getaddr(sock->obj, addrp);
+  }
+
+int nr_socket_close(nr_socket *sock)
+  {
+    return sock->vtbl->close(sock->obj);
+  }
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/net/nr_socket.h
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _nr_socket_h
+#define _nr_socket_h
+
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#endif
+
+#include "transport_addr.h"
+
+#ifdef __cplusplus
+#define restrict
+#elif defined(WIN32)
+#define restrict __restrict
+#endif
+
+typedef struct nr_socket_vtbl_ {
+  int (*destroy)(void **obj);
+  int (*ssendto)(void *obj,const void *msg, size_t len, int flags,
+    nr_transport_addr *addr);
+  int (*srecvfrom)(void *obj,void * restrict buf, size_t maxlen, size_t *len, int flags,
+    nr_transport_addr *addr);
+  int (*getfd)(void *obj, NR_SOCKET *fd);
+  int (*getaddr)(void *obj, nr_transport_addr *addrp);
+  int (*close)(void *obj);
+} nr_socket_vtbl;
+
+typedef struct nr_socket_ {
+  void *obj;
+  nr_socket_vtbl *vtbl;
+} nr_socket;
+
+
+/* To be called by constructors */
+int nr_socket_create_int(void *obj, nr_socket_vtbl *vtbl, nr_socket **sockp);
+int nr_socket_destroy(nr_socket **sockp);
+int nr_socket_sendto(nr_socket *sock,const void *msg, size_t len,
+  int flags,nr_transport_addr *addr);
+int nr_socket_recvfrom(nr_socket *sock,void * restrict buf, size_t maxlen,
+  size_t *len, int flags, nr_transport_addr *addr);
+int nr_socket_getfd(nr_socket *sock, NR_SOCKET *fd);
+int nr_socket_getaddr(nr_socket *sock, nr_transport_addr *addrp);
+int nr_socket_close(nr_socket *sock);
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/net/nr_socket_local.h
@@ -0,0 +1,41 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _nr_socket_local_h
+#define _nr_socket_local_h
+
+int nr_socket_local_create(nr_transport_addr *addr, nr_socket **sockp);
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.c
@@ -0,0 +1,298 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: transport_addr.c,v 1.2 2008/04/28 17:59:03 ekr Exp $";
+
+
+#include <csi_platform.h>
+#include <stdio.h>
+#include <memory.h>
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <assert.h>
+#include "nr_api.h"
+#include "transport_addr.h"
+
+static int fmt_addr_string(nr_transport_addr *addr)
+  {
+    int _status;
+
+    switch(addr->ip_version){
+      case NR_IPV4:
+        snprintf(addr->as_string,40,"IP4:%s:%d",inet_ntoa(addr->u.addr4.sin_addr),ntohs(addr->u.addr4.sin_port));
+        break;
+    default:
+      ABORT(R_INTERNAL);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr)
+  {
+    int r,_status;
+
+    if(!keep) memset(addr,0,sizeof(nr_transport_addr));
+
+    if(saddr->sa_family==PF_INET){
+      if(saddr_len != sizeof(struct sockaddr_in))
+        ABORT(R_BAD_ARGS);
+
+      switch(protocol){
+        case IPPROTO_TCP:
+        case IPPROTO_UDP:
+          break;
+        default:
+          ABORT(R_BAD_ARGS);
+      }
+      addr->ip_version=NR_IPV4;
+      addr->protocol=protocol;
+      
+      memcpy(&addr->u.addr4,saddr,sizeof(struct sockaddr_in));
+      addr->addr=(struct sockaddr *)&addr->u.addr4;
+      addr->addr_len=saddr_len;
+    }
+    else if(saddr->sa_family==PF_INET6){
+      /* Not implemented */
+      ABORT(R_INTERNAL);
+    }
+    else
+      ABORT(R_BAD_ARGS);
+
+    if(r=fmt_addr_string(addr))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+
+int nr_transport_addr_copy(nr_transport_addr *to, nr_transport_addr *from)
+  {
+    memcpy(to,from,sizeof(nr_transport_addr));
+    to->addr=(struct sockaddr *)((char *)to + ((char *)from->addr - (char *)from));
+    
+    return(0);
+  }
+
+/* Convenience fxn. Is this the right API?*/
+int nr_ip4_port_to_transport_addr(UINT4 ip4, UINT2 port, int protocol, nr_transport_addr *addr)
+  {
+    int r,_status;
+
+    memset(addr, 0, sizeof(nr_transport_addr));
+
+    addr->ip_version=NR_IPV4;
+    addr->protocol=protocol;
+#ifdef HAVE_SIN_LEN
+    addr->u.addr4.sin_len=sizeof(struct sockaddr_in);
+#endif
+    addr->u.addr4.sin_family=PF_INET;
+    addr->u.addr4.sin_port=htons(port);
+    addr->u.addr4.sin_addr.s_addr=htonl(ip4);
+    addr->addr=(struct sockaddr *)&addr->u.addr4;
+    addr->addr_len=sizeof(struct sockaddr_in);
+
+    if(r=fmt_addr_string(addr))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ip4_str_port_to_transport_addr(char *ip4, UINT2 port, int protocol, nr_transport_addr *addr)
+  {
+    int r,_status;
+    in_addr_t ip_addr;
+
+    ip_addr=inet_addr(ip4);
+    /* Assume v4 for now */
+    if(r=nr_ip4_port_to_transport_addr(ntohl(ip_addr),port,protocol,addr))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_transport_addr_get_addrstring(nr_transport_addr *addr, char *str, int maxlen)
+  {
+    char buf[100]; // Long enough
+    int _status;
+    
+    switch(addr->ip_version){
+      case NR_IPV4:
+        if(!(addr2ascii(AF_INET, &addr->u.addr4.sin_addr,sizeof(struct in_addr),buf)))
+          ABORT(R_INTERNAL);
+        if(strlen(buf)>(maxlen-1))
+          ABORT(R_BAD_ARGS);
+        strcpy(str,buf);
+        break;
+      case NR_IPV6:
+        UNIMPLEMENTED;
+      default:
+        ABORT(R_INTERNAL);
+    }
+
+            
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_transport_addr_get_port(nr_transport_addr *addr, int *port)
+  {
+    int _status;
+
+    switch(addr->ip_version){
+      case NR_IPV4:
+        *port=ntohs(addr->u.addr4.sin_port);
+        break;
+      case NR_IPV6:
+        *port=ntohs(addr->u.addr6.sin6_port);
+        break;
+      default:
+        ABORT(R_INTERNAL);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_transport_addr_get_ip4(nr_transport_addr *addr, UINT4 *ip4p)
+  {
+    int _status;
+
+    switch(addr->ip_version){
+      case NR_IPV4:
+        *ip4p=ntohl(addr->u.addr4.sin_addr.s_addr);
+        break;
+      case NR_IPV6:
+        ABORT(R_NOT_FOUND);
+        break;
+      default:
+        ABORT(R_INTERNAL);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+/* memcmp() may not work if, for instance, the string or interface
+   haven't been made. Hmmm.. */
+int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode)
+  {
+    assert(mode);
+
+    if(addr1->ip_version != addr2->ip_version)
+      return(1);
+
+    if(mode < NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL)
+      return(0);
+
+    if(addr1->protocol != addr2->protocol)
+      return(1);
+
+    if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ADDR)
+      return(0);
+
+    assert(addr1->addr_len == addr2->addr_len);
+    switch(addr1->ip_version){
+      case NR_IPV4:
+        if(addr1->u.addr4.sin_addr.s_addr != addr2->u.addr4.sin_addr.s_addr)
+          return(1);
+        if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
+          return(0);
+        if(addr1->u.addr4.sin_port != addr2->u.addr4.sin_port)
+          return(1);
+        break;
+      case NR_IPV6:
+        UNIMPLEMENTED;
+      default:
+        abort();
+    }
+
+    return(0);
+  }
+
+int nr_transport_addr_is_loopback(nr_transport_addr *addr)
+  {
+    switch(addr->ip_version){
+      case NR_IPV4:
+        switch(addr->u.addr4.sin_family){
+          case AF_INET:
+            if (((ntohl(addr->u.addr4.sin_addr.s_addr)>>24)&0xff)==0x7f)
+              return 1;
+            break;
+          default:
+            UNIMPLEMENTED;
+            break;
+        }
+        break;
+
+      default:
+        UNIMPLEMENTED;
+    }
+
+    return(0);
+  }
+
+int nr_transport_addr_is_wildcard(nr_transport_addr *addr)
+  {
+    switch(addr->ip_version){
+      case NR_IPV4:
+        if(addr->u.addr4.sin_addr.s_addr==INADDR_ANY)
+          return(1);
+        if(addr->u.addr4.sin_port==0)
+          return(1);
+        break;
+      default:
+        UNIMPLEMENTED;
+    }
+
+    return(0);
+  }
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.h
@@ -0,0 +1,92 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _transport_addr_h
+#define _transport_addr_h
+
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#ifdef WIN32
+#define MAXIFNAME IFNAMSIZ
+#else
+#define MAXIFNAME 16
+#endif
+
+/* Generic transport address
+
+   This spans both sockaddr_in and sockaddr_in6
+ */
+typedef struct nr_transport_addr_ {
+  UCHAR ip_version;  /* 4 or 6 */
+#define NR_IPV4 4
+#define NR_IPV6 6
+  UCHAR protocol;    /* IPPROTO_TCP, IPPROTO_UDP */
+  struct sockaddr *addr;
+  int addr_len;
+  union {
+    struct sockaddr_in addr4;
+    struct sockaddr_in6 addr6;
+  } u;
+  char ifname[MAXIFNAME];
+  char as_string[40];     /* A string version */
+} nr_transport_addr;
+
+int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr);
+
+// addresses, ports in local byte order
+int nr_ip4_port_to_transport_addr(UINT4 ip4, UINT2 port, int protocol, nr_transport_addr *addr);
+int nr_ip4_str_port_to_transport_addr(char *ip4, UINT2 port, int protocol, nr_transport_addr *addr);
+
+int nr_transport_addr_get_addrstring(nr_transport_addr *addr, char *str, int maxlen);
+int nr_transport_addr_get_port(nr_transport_addr *addr, int *port);
+int nr_transport_addr_get_ip4(nr_transport_addr *addr, UINT4 *ip4p);
+int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode);
+#define NR_TRANSPORT_ADDR_CMP_MODE_VERSION   1
+#define NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL  2
+#define NR_TRANSPORT_ADDR_CMP_MODE_ADDR      3
+#define NR_TRANSPORT_ADDR_CMP_MODE_ALL       4
+
+int nr_transport_addr_is_wildcard(nr_transport_addr *addr);
+int nr_transport_addr_is_loopback(nr_transport_addr *addr);
+int nr_transport_addr_copy(nr_transport_addr *to, nr_transport_addr *from);
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
@@ -0,0 +1,214 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: transport_addr_reg.c,v 1.2 2008/04/28 17:59:03 ekr Exp $";
+
+#include <csi_platform.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <strings.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <assert.h>
+#include "nr_api.h"
+#include "transport_addr.h"
+#include "transport_addr_reg.h"
+
+
+int
+nr_reg_get_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr)
+{
+    int r,_status;
+    unsigned int count;
+    char *address = 0;
+    UINT2 port = 0;
+    char *ifname = 0;
+    char *protocol = 0;
+    int p;
+
+    if ((r=NR_reg_get_child_count(prefix, &count)))
+        ABORT(r);
+
+    if (count == 0)
+        ABORT(R_NOT_FOUND);
+
+    if ((r=NR_reg_alloc2_string(prefix, "address", &address))) {
+        if (r != R_NOT_FOUND)
+            ABORT(r);
+        address = 0;
+    }
+
+    if ((r=NR_reg_alloc2_string(prefix, "ifname", &ifname))) {
+        if (r != R_NOT_FOUND)
+            ABORT(r);
+        ifname = 0;
+    }
+
+    if ((r=NR_reg_get2_uint2(prefix, "port", &port))) {
+        if (r != R_NOT_FOUND)
+            ABORT(r);
+        port = 0;
+    }
+
+    if ((r=NR_reg_alloc2_string(prefix, "protocol", &protocol))) {
+        if (r != R_NOT_FOUND)
+            ABORT(r);
+        p = IPPROTO_UDP;
+
+        protocol = 0;
+    }
+    else {
+        if (!strcasecmp("tcp", protocol))
+            p = IPPROTO_TCP;
+        else if (!strcasecmp("udp", protocol))
+            p = IPPROTO_UDP;
+        else
+            ABORT(R_BAD_DATA);
+    }
+
+    if (!keep) memset(addr, 0, sizeof(*addr));
+
+    if ((r=nr_ip4_str_port_to_transport_addr(address?address:"0.0.0.0", port, p, addr)))
+        ABORT(r);
+
+    if (ifname)
+        strlcpy(addr->ifname, ifname, sizeof(addr->ifname));
+
+    _status=0;
+  abort:
+    RFREE(protocol);
+    RFREE(ifname);
+    RFREE(address);
+    return(_status);
+}
+
+int
+nr_reg_set_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr)
+{
+    int r,_status;
+
+    if (! keep) {
+        if ((r=NR_reg_del(prefix)))
+            ABORT(r);
+    }
+
+    switch (addr->ip_version) {
+    case NR_IPV4:
+        if (addr->u.addr4.sin_addr.s_addr != INADDR_ANY) {
+            if ((r=NR_reg_set2_string(prefix, "address", inet_ntoa(addr->u.addr4.sin_addr))))
+                ABORT(r);
+        }
+
+        if (addr->u.addr4.sin_port != 0) {
+            if ((r=NR_reg_set2_uint2(prefix, "port", ntohs(addr->u.addr4.sin_port))))
+                ABORT(r);
+        }
+
+        switch (addr->protocol) {
+        case IPPROTO_TCP:
+            if ((r=NR_reg_set2_string(prefix, "protocol", "tcp")))
+                ABORT(r);
+            break;
+        case IPPROTO_UDP:
+            if ((r=NR_reg_set2_string(prefix, "protocol", "udp")))
+                ABORT(r);
+            break;
+        default:
+            UNIMPLEMENTED;
+            break;
+        }
+
+        if (strlen(addr->ifname) > 0) {
+            if ((r=NR_reg_set2_string(prefix, "ifname", addr->ifname)))
+                ABORT(r);
+        }
+        break;
+
+    case NR_IPV6:
+        UNIMPLEMENTED;
+        break;
+    default:
+        ABORT(R_INTERNAL);
+        break;
+    }
+
+    _status=0;
+  abort:
+    if (_status)
+        NR_reg_del(prefix);
+    return _status;
+}
+
+int
+nr_reg_get_transport_addr2(NR_registry prefix, char *name, int keep, nr_transport_addr *addr)
+{
+    int r, _status;
+    NR_registry registry;
+
+    if ((r=NR_reg_make_registry(prefix, name, registry)))
+        ABORT(r);
+
+    if ((r=nr_reg_get_transport_addr(registry, keep, addr)))
+        ABORT(r);
+
+    _status = 0;
+abort:
+    return _status;
+}
+
+int
+nr_reg_set_transport_addr2(NR_registry prefix, char *name, int keep, nr_transport_addr *addr)
+{
+    int r, _status;
+    NR_registry registry;
+
+    if ((r=NR_reg_make_registry(prefix, name, registry)))
+        ABORT(r);
+
+    if ((r=nr_reg_set_transport_addr(registry, keep, addr)))
+        ABORT(r);
+
+    _status = 0;
+abort:
+    return _status;
+}
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.h
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _transport_addr_reg_h
+#define _transport_addr_reg_h
+
+#include "registry.h"
+
+int nr_reg_get_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr);
+int nr_reg_set_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr);
+int nr_reg_get_transport_addr2(NR_registry prefix, char *name, int keep, nr_transport_addr *addr);
+int nr_reg_set_transport_addr2(NR_registry prefix, char *name, int keep, nr_transport_addr *addr);
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/addrs.c
@@ -0,0 +1,702 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+static char *RCSSTRING __UNUSED__="$Id: addrs.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
+
+
+#include <csi_platform.h>
+#include <assert.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include <tchar.h>
+#else   /* UNIX */
+#include <sys/sysctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <net/if.h>
+#ifndef LINUX
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <sys/sockio.h>
+#else
+#include <linux/if.h>
+#endif
+#include <net/route.h>
+
+/* IP */
+#include <netinet/in.h>
+#ifdef LINUX
+#include "sys/ioctl.h"
+#else
+#include <netinet/in_var.h>
+#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif  /* UNIX */
+
+#include "stun.h"
+#include "addrs.h"
+
+
+
+#ifdef DARWIN
+/*
+ * Copyright (c) 1983, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+
+static void stun_rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
+static int stun_grab_addrs(char *name, int addrcount,
+               struct ifa_msghdr *ifam,
+               nr_transport_addr addrs[], int maxaddrs, int *count);
+static int
+nr_stun_is_duplicate_addr(nr_transport_addr addrs[], int count, nr_transport_addr *addr);
+
+
+/*
+ * Expand the compacted form of addresses as returned via the
+ * configuration read via sysctl().
+ */
+#define ROUNDUP(a) \
+    ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+static void
+stun_rt_xaddrs(cp, cplim, rtinfo)
+    caddr_t cp, cplim;
+    struct rt_addrinfo *rtinfo;
+{
+    struct sockaddr *sa;
+    int i;
+
+    memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
+    for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+        if ((rtinfo->rti_addrs & (1 << i)) == 0)
+            continue;
+        rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+        ADVANCE(cp, sa);
+    }
+}
+
+static int
+stun_grab_addrs(char *name, int addrcount, struct ifa_msghdr *ifam, nr_transport_addr addrs[], int maxaddrs, int *count)
+{
+    int r,_status;
+    int s = -1;
+    struct ifreq ifr;
+    struct rt_addrinfo info;
+    struct sockaddr_in *sin;
+
+    ifr.ifr_addr.sa_family = AF_INET;
+    strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+
+    if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) {
+      r_log(NR_LOG_STUN, LOG_WARNING, "unable to obtain addresses from socket");
+      ABORT(R_FAILED);
+    }
+
+    while (addrcount > 0) {
+        info.rti_addrs = ifam->ifam_addrs;
+
+        /* Expand the compacted addresses */
+        stun_rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
+
+        switch (info.rti_info[RTAX_IFA]->sa_family) {
+        case AF_INET:
+            sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
+
+            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sin, sizeof(*sin), IPPROTO_UDP, 0, &(addrs[*count]))))
+                ABORT(r);
+
+            strlcpy(addrs[*count].ifname, name, sizeof(addrs[*count].ifname));
+
+            ++*count;
+            break;
+        case AF_INET6:
+            UNIMPLEMENTED;
+            break;
+        }
+
+        addrcount--;
+
+        if (*count >= maxaddrs) {
+            r_log(NR_LOG_STUN, LOG_WARNING, "Address list truncated at %d out of entries", maxaddrs, maxaddrs+addrcount);
+            break;
+        }
+
+        ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
+    }
+
+    _status = 0;
+  abort:
+    if (s != -1) close(s);
+    return _status;
+}
+
+static int
+stun_get_mib_addrs(nr_transport_addr addrs[], int maxaddrs, int *count)
+{
+    int _status;
+    char name[32];
+    int flags;
+    int addrcount;
+    struct if_msghdr *ifm, *nextifm;
+    struct ifa_msghdr *ifam;
+    struct sockaddr_dl *sdl;
+    char *buf = 0;
+    char *lim;
+    char *next;
+    size_t needed;
+    int mib[6];
+
+    *count = 0;
+
+    mib[0] = CTL_NET;
+    mib[1] = PF_ROUTE;
+    mib[2] = 0;
+    mib[3] = AF_INET;
+    mib[4] = NET_RT_IFLIST;
+    mib[5] = 0;
+
+    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+        errx(1, "iflist-sysctl-estimate");
+    if ((buf = malloc(needed)) == NULL)
+        errx(1, "malloc");
+    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+        errx(1, "actual retrieval of interface table");
+    lim = buf + needed;
+
+    next = buf;
+    while (next < lim) {
+        ifm = (struct if_msghdr *)next;
+
+        if (ifm->ifm_type == RTM_IFINFO) {
+            sdl = (struct sockaddr_dl *)(ifm + 1);
+            flags = ifm->ifm_flags;
+        } else {
+            r_log(NR_LOG_STUN, LOG_WARNING, "out of sync parsing NET_RT_IFLIST");
+            r_log(NR_LOG_STUN, LOG_DEBUG, "expected %d, got %d, msglen = %d, buf:%p, next:%p, lim:%p", RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, buf, next, lim);
+            ABORT(R_FAILED);
+        }
+
+        next += ifm->ifm_msglen;
+        ifam = NULL;
+        addrcount = 0;
+        while (next < lim) {
+
+            nextifm = (struct if_msghdr *)next;
+
+            if (nextifm->ifm_type != RTM_NEWADDR)
+                break;
+
+            if (ifam == NULL)
+                ifam = (struct ifa_msghdr *)nextifm;
+
+            addrcount++;
+            next += nextifm->ifm_msglen;
+        }
+
+        strncpy(name, sdl->sdl_data, sdl->sdl_nlen);
+        name[sdl->sdl_nlen] = '\0';
+
+        stun_grab_addrs(name, addrcount, ifam, addrs, maxaddrs, count);
+    }
+
+    _status = 0;
+abort:
+    if (buf) free(buf);
+    return _status;
+}
+
+#elif defined(WIN32)
+
+#define WIN32_MAX_NUM_INTERFACES  20
+
+
+#define _NR_MAX_KEY_LENGTH 256
+#define _NR_MAX_NAME_LENGTH 512
+
+#define _ADAPTERS_BASE_REG "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+static int nr_win32_get_adapter_friendly_name(char *adapter_GUID, char **friendly_name)
+{
+    int r,_status;
+    HKEY adapter_reg;
+    TCHAR adapter_key[_NR_MAX_KEY_LENGTH];
+	TCHAR keyval_buf[_NR_MAX_KEY_LENGTH];
+    TCHAR adapter_GUID_tchar[_NR_MAX_NAME_LENGTH];
+    DWORD keyval_len, key_type;
+    size_t converted_chars, newlen;
+    char *my_fn = 0;
+
+#ifdef _UNICODE
+    mbstowcs_s(&converted_chars, adapter_GUID_tchar, strlen(adapter_GUID)+1,
+               adapter_GUID, _TRUNCATE);
+#else
+    strncpy(adapter_GUID_tchar, _NR_MAX_NAME_LENGTH, adapter_GUID);
+#endif
+
+    _tcscpy_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT(_ADAPTERS_BASE_REG));
+    _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT("\\"));
+    _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, adapter_GUID_tchar);
+    _tcscat_s(adapter_key, _NR_MAX_KEY_LENGTH, TEXT("\\Connection"));
+
+	r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, adapter_key, 0, KEY_READ, &adapter_reg);
+
+    if (r != ERROR_SUCCESS) {
+      r_log(NR_LOG_STUN, LOG_ERR, "Got error %d opening adapter reg key\n", r);
+      ABORT(R_INTERNAL);
+    }
+
+    keyval_len = sizeof(keyval_buf);
+    r = RegQueryValueEx(adapter_reg, TEXT("Name"), NULL, &key_type,
+                        (BYTE *)keyval_buf, &keyval_len);
+
+    RegCloseKey(adapter_reg);
+
+#ifdef UNICODE
+    newlen = wcslen(keyval_buf)+1;
+    my_fn = (char *) RCALLOC(newlen);
+    if (!my_fn) {
+      ABORT(R_NO_MEMORY); 
+    }
+    wcstombs_s(&converted_chars, my_fn, newlen, keyval_buf, _TRUNCATE);
+#else
+    my_fn = r_strdup(keyval_buf);
+#endif
+
+    *friendly_name = my_fn;
+    _status=0;
+
+abort:
+    if (_status) {
+      if (my_fn) free(my_fn);
+    }
+    return(_status);
+}
+
+
+static int
+stun_get_win32_addrs(nr_transport_addr addrs[], int maxaddrs, int *count)
+{
+    int r,_status;
+    PIP_ADAPTER_INFO pAdapterInfo;
+    PIP_ADAPTER_INFO pAdapter = NULL;
+    PIP_ADDR_STRING pAddrString;
+    ULONG out_buf_len;
+    char *friendly_name=0;
+    char munged_ifname[IFNAMSIZ];
+    int n = 0;
+
+    *count = 0;
+
+    pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(sizeof(IP_ADAPTER_INFO));
+    out_buf_len = sizeof(IP_ADAPTER_INFO);
+
+    /* First call to GetAdaptersInfo is mainly to get length */
+
+    if (GetAdaptersInfo(pAdapterInfo, &out_buf_len) == ERROR_BUFFER_OVERFLOW) {
+      RFREE(pAdapterInfo);
+      pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(out_buf_len);
+      if (pAdapterInfo == NULL) {
+        r_log(NR_LOG_STUN, LOG_ERR, "Error allocating memory for GetAdaptersInfo output");
+        ABORT(R_NO_MEMORY);
+      }
+    }
+    if ((r = GetAdaptersInfo(pAdapterInfo, &out_buf_len)) != NO_ERROR) {
+      r_log(NR_LOG_STUN, LOG_ERR, "Got error from GetAdaptersInfo");
+      ABORT(R_INTERNAL);
+    }
+    r_log(NR_LOG_STUN, LOG_DEBUG, "Got AdaptersInfo");
+
+    pAdapter = pAdapterInfo;
+
+    while (pAdapter) {
+      char *c;
+
+      r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Name (GUID) = %s", pAdapter->AdapterName);
+      r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Description = %s", pAdapter->Description);
+
+      if ((r = nr_win32_get_adapter_friendly_name(pAdapter->AdapterName, &friendly_name))) {
+        r_log(NR_LOG_STUN, LOG_ERR, "Error %d getting friendly name for adapter with GUID = %s", r, 
+              pAdapter->AdapterName);
+        ABORT(r);
+      }
+
+      r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with friendly name: %s", friendly_name);
+
+      snprintf(munged_ifname, IFNAMSIZ, "%s%c", friendly_name, 0);
+      RFREE(friendly_name);
+      friendly_name = 0;
+
+      /* replace spaces with underscores */
+      c = strchr(munged_ifname, ' ');
+      while (c != NULL) {
+        *c = '_';
+         c = strchr(munged_ifname, ' ');
+      }
+      c = strchr(munged_ifname, '.'); 
+      while (c != NULL) {
+        *c = '+';
+         c = strchr(munged_ifname, '+'); 
+      }
+
+      r_log(NR_LOG_STUN, LOG_INFO, "Converted ifname: %s", munged_ifname);
+
+      for (pAddrString = &(pAdapter->IpAddressList); pAddrString != NULL; pAddrString = pAddrString->Next) {
+        unsigned long this_addr = inet_addr(pAddrString->IpAddress.String);
+
+        if (this_addr == 0)
+          continue;
+
+        r_log(NR_LOG_STUN, LOG_INFO, "Adapter %s address: %s", munged_ifname, pAddrString->IpAddress.String);
+
+        addrs[n].ip_version=NR_IPV4;
+        addrs[n].protocol = IPPROTO_UDP; 
+
+        addrs[n].u.addr4.sin_family=PF_INET;
+        addrs[n].u.addr4.sin_port=0;
+        addrs[n].u.addr4.sin_addr.s_addr=this_addr;
+        addrs[n].addr=(struct sockaddr *)&(addrs[n].u.addr4);
+        addrs[n].addr_len=sizeof(struct sockaddr_in);
+
+        strncpy(addrs[n].ifname, munged_ifname, sizeof(addrs[n].ifname));
+        snprintf(addrs[n].as_string,40,"IP4:%s:%d",inet_ntoa(addrs[n].u.addr4.sin_addr),
+                 ntohs(addrs[n].u.addr4.sin_port));
+
+        if (++n >= maxaddrs)
+          goto done;
+      }
+
+      pAdapter = pAdapter->Next;
+    }
+
+  done:
+    *count = n;
+    _status = 0;
+
+  abort:
+    RFREE(pAdapterInfo);
+    RFREE(friendly_name);
+    return _status;
+}
+
+#ifdef GET_WIN32_ADDRS_NO_WIN2K
+   /* Here's a nice way to get adapter addresses and names, but it
+    * isn't supported on Win2000.
+    */
+static int
+stun_get_win32_addrs(nr_transport_addr addrs[], int maxaddrs, int *count)
+{
+    int r,_status;
+    PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL, tmpAddress = NULL;
+    ULONG buflen;
+    char munged_ifname[IFNAMSIZ];
+    int n = 0;
+
+    *count = 0;
+
+    if (maxaddrs <= 0)
+      ABORT(R_INTERNAL);
+
+    /* Call GetAdaptersAddresses() twice.  First, just to get the buf length */
+
+    buflen = 0;
+
+    r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
+    if (r != ERROR_BUFFER_OVERFLOW) {
+      r_log(NR_LOG_STUN, LOG_ERR, "Error getting buf len from GetAdaptersAddresses()");
+      ABORT(R_INTERNAL);
+    }
+        
+    AdapterAddresses = (PIP_ADAPTER_ADDRESSES) RMALLOC(buflen);
+    if (AdapterAddresses == NULL) {
+      r_log(NR_LOG_STUN, LOG_ERR, "Error allocating buf for GetAdaptersAddresses()");
+      ABORT(R_NO_MEMORY);
+    }
+
+    /* for real, this time */
+
+    r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
+    if (r != NO_ERROR) {
+      r_log(NR_LOG_STUN, LOG_ERR, "Error getting addresses from GetAdaptersAddresses()");
+      ABORT(R_INTERNAL);
+    }
+
+    /* Loop through the adapters */
+
+    for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) {
+      char *c;
+        
+      if (tmpAddress->OperStatus != IfOperStatusUp)
+        continue;
+
+      snprintf(munged_ifname, IFNAMSIZ, "%S%c", tmpAddress->FriendlyName, 0);
+      /* replace spaces with underscores */
+      c = strchr(munged_ifname, ' '); 
+      while (c != NULL) {
+        *c = '_';
+         c = strchr(munged_ifname, ' '); 
+      }
+      c = strchr(munged_ifname, '.'); 
+      while (c != NULL) {
+        *c = '+';
+         c = strchr(munged_ifname, '+'); 
+      }
+
+      if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) {
+        IP_ADAPTER_UNICAST_ADDRESS *u = 0;
+        
+        for (u = tmpAddress->FirstUnicastAddress; u != 0; u = u->Next) {
+          SOCKET_ADDRESS *sa_addr = &u->Address;
+
+          if ((sa_addr->lpSockaddr->sa_family == AF_INET) ||
+              (sa_addr->lpSockaddr->sa_family == AF_INET6)) {
+            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, sizeof(*sa_addr->lpSockaddr), IPPROTO_UDP, 0, &(addrs[n]))))
+                ABORT(r);
+          }
+          else {
+            r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized sa_family for adapteraddress %s",munged_ifname);
+            continue;
+          }
+
+          strncpy(addrs[n].ifname, munged_ifname, sizeof(addrs[n].ifname));
+          if (++n >= maxaddrs)
+            goto done;
+        }
+      }
+    }
+
+   done:
+    *count = n;
+    _status = 0;
+
+  abort:
+    RFREE(AdapterAddresses);
+    return _status;
+}
+#endif  /* GET_WIN32_ADDRS_NO_WIN2K */
+
+#elif defined(__sparc__)
+
+static int
+stun_get_sparc_addrs(nr_transport_addr addrs[], int maxaddrs, int *count)
+{
+    *count = 0;
+    UNIMPLEMENTED; /*TODO !nn! - sparc */
+    return 0;
+}
+
+#else
+
+static int
+stun_get_siocgifconf_addrs(nr_transport_addr addrs[], int maxaddrs, int *count)
+{
+   struct ifconf ifc;
+   int _status;
+   int s = socket( AF_INET, SOCK_DGRAM, 0 );
+   int len = 100 * sizeof(struct ifreq);
+   int r;
+   int e;
+   char *ptr;
+   int tl;
+   int n;
+   struct ifreq ifr2;
+
+   char buf[ len ];
+
+   ifc.ifc_len = len;
+   ifc.ifc_buf = buf;
+
+   e = ioctl(s,SIOCGIFCONF,&ifc);
+   ptr = buf;
+   tl = ifc.ifc_len;
+   n=0;
+
+   while ( (tl > 0) && ( n < maxaddrs) )
+   {
+      struct ifreq* ifr = (struct ifreq *)ptr;
+
+#ifdef LINUX
+      int si = sizeof(struct ifreq);
+#else
+      int si = sizeof(ifr->ifr_name) + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr));
+#endif
+      tl -= si;
+      ptr += si;
+
+      ifr2 = *ifr;
+
+      e = ioctl(s,SIOCGIFADDR,&ifr2);
+      if ( e == -1 )
+      {
+          continue;
+      }
+
+      //r_log(NR_LOG_STUN, LOG_ERR, "ioctl addr e = %d",e);
+
+      if ((r=nr_sockaddr_to_transport_addr(&ifr2.ifr_addr, sizeof(ifr2.ifr_addr), IPPROTO_UDP, 0, &(addrs[n])))) {
+          r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
+      }
+      else {
+          strlcpy(addrs[n].ifname, ifr->ifr_name, sizeof(addrs[n].ifname));
+          ++n;
+      }
+   }
+
+   close(s);
+
+   *count = n;
+
+    _status = 0;
+    return _status;
+}
+#endif
+
+static int
+nr_stun_is_duplicate_addr(nr_transport_addr addrs[], int count, nr_transport_addr *addr)
+{
+    int i;
+    int different;
+
+    for (i = 0; i < count; ++i) {
+        different = nr_transport_addr_cmp(&addrs[i], addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL);
+        if (!different) 
+            return 1;  /* duplicate */
+    }
+
+    return 0;
+}
+
+int
+nr_stun_remove_duplicate_addrs(nr_transport_addr addrs[], int remove_loopback, int *count)
+{
+    int r, _status;
+    nr_transport_addr *tmp = 0;
+    int i;
+    int n;
+
+    tmp = RMALLOC(*count * sizeof(*tmp));
+    if (!tmp)
+        ABORT(R_NO_MEMORY);
+
+    n = 0;
+    for (i = 0; i < *count; ++i) {
+        if (nr_stun_is_duplicate_addr(tmp, n, &addrs[i])) {
+            /* skip addrs[i], it's a duplicate */
+        }
+        else if (remove_loopback && nr_transport_addr_is_loopback(&addrs[i])) {
+            /* skip addrs[i], it's a loopback */
+        }
+        else {
+            /* otherwise, copy it to the temporary array */
+            if ((r=nr_transport_addr_copy(&tmp[n], &addrs[i])))
+                ABORT(r);
+            ++n;
+        }
+    }
+
+    *count = n;
+
+    /* copy temporary array into passed in/out array */
+    for (i = 0; i < *count; ++i) {
+        if ((r=nr_transport_addr_copy(&addrs[i], &tmp[i])))
+            ABORT(r);
+    }
+
+    _status = 0;
+  abort:
+    RFREE(tmp);
+    return _status;
+}
+
+int
+nr_stun_get_addrs(nr_transport_addr addrs[], int maxaddrs, int drop_loopback, int *count)
+{
+    int _status=0;
+    int i;
+
+#ifdef DARWIN
+    _status = stun_get_mib_addrs(addrs, maxaddrs, count);
+#elif defined(WIN32)
+    _status = stun_get_win32_addrs(addrs, maxaddrs, count);
+#elif defined(__sparc__)
+    _status = stun_get_sparc_addrs(addrs, maxaddrs, count);
+#else
+    _status = stun_get_siocgifconf_addrs(addrs, maxaddrs, count);
+#endif
+
+    nr_stun_remove_duplicate_addrs(addrs, drop_loopback, count);
+
+    for (i = 0; i < *count; ++i) {
+        r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s", i, addrs[i].as_string, addrs[i].ifname);
+    }
+
+    return _status;
+}
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/addrs.h
@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef _addrs_h_
+#define _addrs_h_
+
+#include "transport_addr.h"
+
+int nr_stun_get_addrs(nr_transport_addr addrs[], int maxaddrs, int remove_loopback, int *count);
+int nr_stun_remove_duplicate_addrs(nr_transport_addr addrs[], int remove_loopback,int *count);
+
+#endif
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/nr_socket_turn.c
@@ -0,0 +1,264 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: nr_socket_turn.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
+
+#ifdef USE_TURN
+
+#include <csi_platform.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include "stun.h"
+#include "nr_socket_turn.h"
+#include "turn_client_ctx.h"
+
+
+static char *nr_socket_turn_magic_cookie = "nr_socket_turn";
+
+typedef struct nr_socket_turn_ {
+  char *magic_cookie;
+  int turn_state;
+  nr_socket *sock;
+  nr_transport_addr relay_addr;
+} nr_socket_turn;
+
+
+static int nr_socket_turn_destroy(void **objp);
+static int nr_socket_turn_sendto(void *obj,const void *msg, size_t len,
+  int flags, nr_transport_addr *to);
+static int nr_socket_turn_recvfrom(void *obj,void * restrict buf,
+  size_t maxlen, size_t *len, int flags, nr_transport_addr *from);
+static int nr_socket_turn_getfd(void *obj, NR_SOCKET *fd);
+static int nr_socket_turn_getaddr(void *obj, nr_transport_addr *addrp);
+static int nr_socket_turn_close(void *obj);
+
+static nr_socket_vtbl nr_socket_turn_vtbl={
+  nr_socket_turn_destroy,
+  nr_socket_turn_sendto,
+  nr_socket_turn_recvfrom,
+  nr_socket_turn_getfd,
+  nr_socket_turn_getaddr,
+  nr_socket_turn_close
+};
+
+int nr_socket_turn_create(nr_socket *sock, int turn_state, nr_socket **sockp)
+  {
+    int r,_status;
+    nr_socket_turn *sturn=0;
+
+    if(!(sturn=RCALLOC(sizeof(nr_socket_turn))))
+      ABORT(R_NO_MEMORY);
+
+    sturn->magic_cookie = nr_socket_turn_magic_cookie;
+    sturn->sock=sock;
+    sturn->turn_state=turn_state;
+
+    if(r=nr_socket_create_int(sturn, &nr_socket_turn_vtbl, sockp))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    if(_status){
+      nr_socket_turn_destroy((void **)&sturn);
+    }
+    return(_status);
+  }
+
+void nr_socket_turn_set_state(nr_socket *sock, int turn_state)
+{
+    nr_socket_turn *sturn=(nr_socket_turn*)sock->obj;
+    assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+
+    sturn->turn_state=turn_state;
+}
+
+void nr_socket_turn_set_relay_addr(nr_socket *sock, nr_transport_addr *relay)
+{
+    nr_socket_turn *sturn=(nr_socket_turn*)sock->obj;
+    assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+
+    nr_transport_addr_copy(&sturn->relay_addr, relay);
+}
+
+
+static int nr_socket_turn_destroy(void **objp)
+  {
+    int _status;
+    nr_socket_turn *sturn;
+
+    if(!objp || !*objp)
+      return(0);
+
+    sturn=*objp;
+    *objp=0;
+
+    assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+
+    /* we don't own the socket, so don't destroy it */
+
+    RFREE(sturn);
+
+    _status=0;
+/*  abort:*/
+    return(_status);
+  }
+
+static int nr_socket_turn_sendto(void *obj,const void *msg, size_t len,
+  int flags, nr_transport_addr *addr)
+  {
+    int r,_status;
+    nr_socket_turn *sturn=obj;
+    assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+
+    switch (sturn->turn_state) {
+    case NR_TURN_CLIENT_STATE_INITTED:
+        if ((r=nr_socket_sendto(sturn->sock,msg,len,flags,addr)))
+            ABORT(r);
+        break;
+#if 0
+/* ACTIVE mode not implemented yet */
+    case NR_TURN_CLIENT_STATE_ACTIVE:
+        if (!nr_has_stun_cookie((char*)msg,len)) {
+            if ((r=nr_socket_sendto(sturn->sock,msg,len,flags,addr)))
+                ABORT(r);
+            break;  /* BREAK */
+        }
+        /* FALL THROUGH */
+#endif
+    case NR_TURN_CLIENT_STATE_ALLOCATED:
+        if ((r=nr_turn_client_relay_indication_data(sturn->sock, msg, len, flags, &sturn->relay_addr, addr)))
+            ABORT(r);
+        break;
+    default:
+        ABORT(R_INTERNAL);
+        break;
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+static int nr_socket_turn_recvfrom(void *obj,void * restrict buf,
+  size_t maxlen, size_t *len, int flags, nr_transport_addr *addr)
+  {
+    int r,_status;
+    nr_socket_turn *sturn=obj;
+
+    assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+
+    if ((r=nr_socket_recvfrom(sturn->sock,buf,maxlen,len,flags,addr)))
+        ABORT(r);
+
+    switch (sturn->turn_state) {
+    case NR_TURN_CLIENT_STATE_INITTED:
+        /* just pass the data through verbatim */
+        break;
+#if 0
+/* ACTIVE mode not implemented yet */
+    case NR_TURN_CLIENT_STATE_ACTIVE:
+       if (!nr_has_stun_cookie(buf,len)) {
+           break;  /* BREAK */
+       }
+       /* FALL THROUGH */
+#endif
+    case NR_TURN_CLIENT_STATE_ALLOCATED:
+        assert(nr_has_stun_cookie(buf,*len));
+        if ((r=nr_turn_client_rewrite_indication_data(buf, *len, len, addr))) {
+            if (!nr_is_stun_message(buf,*len)) {
+                r_log_nr(NR_LOG_TURN,LOG_WARNING,r,"TURN_SOCKET: Discarding unexpected data");
+
+            }
+            else {
+                r_log(NR_LOG_TURN,LOG_DEBUG,"TURN_SOCKET: Discarding unexpected or retransmitted message");
+            }
+
+            *len = 0;
+        }
+        break;
+    default:
+        ABORT(R_INTERNAL);
+        break;
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+static int nr_socket_turn_getfd(void *obj, NR_SOCKET *fd)
+  {
+    nr_socket_turn *sturn=obj;
+    assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+    return nr_socket_getfd(sturn->sock,fd);
+  }
+
+static int nr_socket_turn_getaddr(void *obj, nr_transport_addr *addrp)
+  {
+    nr_socket_turn *sturn=obj;
+    assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+#if 0
+//    return nr_socket_getaddr(sturn->sock,addrp);
+// not sure if this the following is correct, but the above doesn't
+// seem to work either
+#endif
+    switch (sturn->turn_state) {
+    case NR_TURN_CLIENT_STATE_INITTED:
+        return nr_socket_getaddr(sturn->sock,addrp);
+        break;
+    case NR_TURN_CLIENT_STATE_ALLOCATED:
+        return nr_transport_addr_copy(addrp, &sturn->relay_addr);
+        break;
+    default:
+        assert(0);
+        break;
+    }
+
+    return R_FAILED;
+  }
+
+static int nr_socket_turn_close(void *obj)
+  {
+#ifndef NDEBUG
+    nr_socket_turn *sturn=obj;
+    assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+#endif
+
+    return 0;
+  }
+
+#endif /* USE_TURN */
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/nr_socket_turn.h
@@ -0,0 +1,43 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+#ifndef _nr_socket_turn_h
+#define _nr_socket_turn_h
+
+int nr_socket_turn_create(nr_socket *sock, int turn_state, nr_socket **sockp);
+void nr_socket_turn_set_state(nr_socket *sock, int turn_state);
+void nr_socket_turn_set_relay_addr(nr_socket *sock, nr_transport_addr *relay);
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/stun.h
@@ -0,0 +1,205 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef _STUN_H
+#define _STUN_H
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#ifndef LINUX
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#endif
+#include <net/route.h>
+#include <netinet/in.h>
+#ifndef LINUX
+#include <netinet/in_var.h>
+#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+#include <time.h>
+
+#include "nr_api.h"
+#include "stun_msg.h"
+#include "stun_build.h"
+#include "stun_codec.h"
+#include "stun_hint.h"
+#include "stun_util.h"
+#include "nr_socket.h"
+#include "stun_client_ctx.h"
+#include "stun_server_ctx.h"
+#include "stun_proc.h"
+
+#define NR_STUN_VERSION                 "rfc3489bis-11"
+#define NR_STUN_PORT                    3478
+
+/* STUN attributes */
+#define NR_STUN_ATTR_MAPPED_ADDRESS          0x0001
+#define NR_STUN_ATTR_USERNAME                0x0006
+#define NR_STUN_ATTR_MESSAGE_INTEGRITY       0x0008
+#define NR_STUN_ATTR_ERROR_CODE              0x0009
+#define NR_STUN_ATTR_UNKNOWN_ATTRIBUTES      0x000A
+#define NR_STUN_ATTR_REALM                   0x0014
+#define NR_STUN_ATTR_NONCE                   0x0015
+#define NR_STUN_ATTR_XOR_MAPPED_ADDRESS      0x0020
+#define NR_STUN_ATTR_SERVER                  0x8022
+#define NR_STUN_ATTR_ALTERNATE_SERVER        0x8023
+#define NR_STUN_ATTR_FINGERPRINT             0x8028
+
+/* for backwards compatibility with obsolete versions of the STUN spec */
+#define NR_STUN_ATTR_OLD_XOR_MAPPED_ADDRESS  0x8020
+
+#ifdef USE_STUND_0_96
+#define NR_STUN_ATTR_OLD_CHANGE_REQUEST      0x0003
+#endif /* USE_STUND_0_96 */
+
+#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
+/* for backwards compatibility with obsolete versions of the STUN spec */
+#define NR_STUN_ATTR_OLD_PASSWORD            0x0007
+#define NR_STUN_ATTR_OLD_RESPONSE_ADDRESS    0x0002
+#define NR_STUN_ATTR_OLD_SOURCE_ADDRESS      0x0004
+#define NR_STUN_ATTR_OLD_CHANGED_ADDRESS     0x0005
+#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
+
+#ifdef USE_ICE
+/* ICE attributes */
+#define NR_STUN_ATTR_PRIORITY                0x0024
+#define NR_STUN_ATTR_USE_CANDIDATE           0x0025
+#define NR_STUN_ATTR_ICE_CONTROLLED          0x8029
+#define NR_STUN_ATTR_ICE_CONTROLLING         0x802A
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+/* TURN attributes */
+#define NR_STUN_ATTR_LIFETIME                0x000d
+#define NR_STUN_ATTR_BANDWIDTH               0x0010
+#define NR_STUN_ATTR_REMOTE_ADDRESS          0x0012
+#define NR_STUN_ATTR_DATA                    0x0013
+#define NR_STUN_ATTR_RELAY_ADDRESS           0x0016
+//#define NR_STUN_ATTR_REQUESTED_PORT_PROPS    0x0018    /* UINT4 */
+//#define NR_STUN_ATTR_REQUESTED_TRANSPORT     0x0019    /* UINT4 */
+//#define NR_STUN_ATTR_TIMER_VAL               0x0021    /* ? */
+//#define NR_STUN_ATTR_REQUIRED_IP             0x0022    /* address */
+//#define NR_STUN_ATTR_CONNECT_STAT            0x0023    /* UINT4 */
+#endif /* USE_TURN */
+
+/*
+ *                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *                |M|M|M|M|M|C|M|M|M|C|M|M|M|M|
+ *                |1|1|9|8|7|1|6|5|4|0|3|2|1|0|
+ *                |1|0| | | | | | | | | | | | |
+ *                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *      Figure 3: Format of STUN Message Type Field
+ */
+#define NR_STUN_METHOD_TYPE_BITS(m) \
+        ((((m) & 0xf80) << 2) | (((m) & 0x070) << 1) | ((m) & 0x00f))
+
+#define NR_STUN_CLASS_TYPE_BITS(c) \
+        ((((c) & 0x002) << 7) | (((c) & 0x001) << 4))
+
+#define NR_STUN_GET_TYPE_METHOD(t) \
+        ((((t) >> 2) & 0xf80) | (((t) >> 1) & 0x070) | ((t) & 0x00f))
+
+#define NR_STUN_GET_TYPE_CLASS(t) \
+        ((((t) >> 7) & 0x002) | (((t) >> 4) & 0x001))
+
+#define NR_STUN_TYPE(m,c)  (NR_STUN_METHOD_TYPE_BITS((m)) | NR_STUN_CLASS_TYPE_BITS((c)))
+
+/* building blocks for message types */
+#define NR_METHOD_BINDING          0x001
+#define NR_CLASS_REQUEST           0x0
+#define NR_CLASS_INDICATION        0x1
+#define NR_CLASS_RESPONSE          0x2
+#define NR_CLASS_ERROR_RESPONSE    0x3
+
+/* define types for STUN messages */
+#define NR_STUN_MSG_BINDING_REQUEST                 NR_STUN_TYPE(NR_METHOD_BINDING, \
+                                                                 NR_CLASS_REQUEST)
+#define NR_STUN_MSG_BINDING_INDICATION              NR_STUN_TYPE(NR_METHOD_BINDING, \
+                                                                 NR_CLASS_INDICATION)
+#define NR_STUN_MSG_BINDING_RESPONSE                NR_STUN_TYPE(NR_METHOD_BINDING, \
+                                                                 NR_CLASS_RESPONSE)
+#define NR_STUN_MSG_BINDING_ERROR_RESPONSE          NR_STUN_TYPE(NR_METHOD_BINDING, \
+                                                                 NR_CLASS_ERROR_RESPONSE)
+
+#ifdef USE_TURN
+/* building blocks for TURN message types */
+#define NR_METHOD_ALLOCATE                 0x003
+#define NR_METHOD_SET_ACTIVE_DEST          0x004
+#define NR_METHOD_CONNECT                  0x005
+#define NR_METHOD_SEND                     0x006
+#define NR_METHOD_DATA                     0x007
+#define NR_METHOD_CONNECT_STATUS           0x008
+
+/* define types for a TURN message */
+#define NR_STUN_MSG_ALLOCATE_REQUEST                NR_STUN_TYPE(NR_METHOD_ALLOCATE, \
+                                                                 NR_CLASS_REQUEST)
+#define NR_STUN_MSG_ALLOCATE_RESPONSE               NR_STUN_TYPE(NR_METHOD_ALLOCATE, \
+                                                                 NR_CLASS_RESPONSE)
+#define NR_STUN_MSG_ALLOCATE_ERROR_RESPONSE         NR_STUN_TYPE(NR_METHOD_ALLOCATE, \
+                                                                 NR_CLASS_ERROR_RESPONSE)
+#define NR_STUN_MSG_SET_ACTIVE_DEST_REQUEST         NR_STUN_TYPE(NR_METHOD_SET_ACTIVE_DEST, \
+                                                                 NR_CLASS_REQUEST)
+#define NR_STUN_MSG_SET_ACTIVE_DEST_RESPONSE        NR_STUN_TYPE(NR_METHOD_SET_ACTIVE_DEST, \
+                                                                 NR_CLASS_RESPONSE)
+#define NR_STUN_MSG_SET_ACTIVE_DEST_ERROR_RESPONSE  NR_STUN_TYPE(NR_METHOD_SET_ACTIVE_DEST, \
+                                                                 NR_CLASS_ERROR_RESPONSE)
+#define NR_STUN_MSG_SEND_INDICATION                 NR_STUN_TYPE(NR_METHOD_SEND, \
+                                                                 NR_CLASS_INDICATION)
+#define NR_STUN_MSG_DATA_INDICATION                 NR_STUN_TYPE(NR_METHOD_DATA, \
+                                                                 NR_CLASS_INDICATION)
+#if 0
+#define NR_STUN_MSG_CONNECT_REQUEST                 NR_STUN_TYPE(NR_METHOD_CONNECT, \
+                                                                 NR_CLASS_REQUEST)
+#define NR_STUN_MSG_CONNECT_RESPONSE                NR_STUN_TYPE(NR_METHOD_CONNECT, \
+                                                                 NR_CLASS_RESPONSE)
+#define NR_STUN_MSG_CONNECT_ERROR_RESPONSE          NR_STUN_TYPE(NR_METHOD_CONNECT, \
+                                                                 NR_CLASS_ERROR_RESPONSE)
+#define NR_STUN_MSG_CONNECT_STATUS_INDICATION       NR_STUN_TYPE(NR_METHOD_CONNECT_STATUS, \
+                                                                 NR_CLASS_INDICATION)
+#endif
+#endif /* USE_TURN */
+
+
+#define NR_STUN_AUTH_RULE_OPTIONAL      (1<<0)
+#define NR_STUN_AUTH_RULE_SHORT_TERM    (1<<8)
+#define NR_STUN_AUTH_RULE_LONG_TERM     (1<<9)
+
+#endif
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_build.c
@@ -0,0 +1,497 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+static char *RCSSTRING __UNUSED__="$Id: stun_build.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
+
+#include <csi_platform.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "nr_api.h"
+#include "stun.h"
+#include "registry.h"
+#include "stun_reg.h"
+#include "nr_crypto.h"
+
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 7.1 */
+/* draft-ietf-behave-rfc3489bis-10.txt S 10.1.1 */
+/* note that S 10.1.1 states the message MUST include MESSAGE-INTEGRITY
+ * and USERNAME, but that's not correct -- for instance ICE keepalive
+ * messages don't include these (See draft-ietf-mmusic-ice-18.txt S 10:
+ * "If STUN is being used for keepalives, a STUN Binding Indication is
+ * used.  The Indication MUST NOT utilize any authentication mechanism")
+ */
+int
+nr_stun_form_request_or_indication(int mode, int msg_type, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *req = 0;
+
+   assert(NR_STUN_GET_TYPE_CLASS(msg_type) == NR_CLASS_REQUEST
+       || NR_STUN_GET_TYPE_CLASS(msg_type) == NR_CLASS_INDICATION);
+
+   *msg = 0;
+
+   if ((r=nr_stun_message_create(&req)))
+       ABORT(r);
+
+   req->header.type = msg_type;
+
+   nr_crypto_random_bytes((UCHAR*)&req->header.id,sizeof(req->header.id));
+
+   switch (mode) {
+   default:
+       req->header.magic_cookie = NR_STUN_MAGIC_COOKIE;
+
+       if ((r=nr_stun_message_add_fingerprint_attribute(req)))
+           ABORT(r);
+
+       break;
+
+#ifdef USE_STUND_0_96
+   case NR_STUN_MODE_STUND_0_96:
+       req->header.magic_cookie = NR_STUN_MAGIC_COOKIE2;
+
+       /* actually, stund 0.96 just ignores the fingerprint
+        * attribute, but don't bother to send it */
+
+       break;
+#endif /* USE_STUND_0_96 */
+
+   }
+
+   *msg = req;
+
+   _status=0;
+ abort:
+   if (_status) RFREE(req);
+   return _status;
+}
+
+int
+nr_stun_build_req_lt_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *req = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_username_attribute(req, params->username)))
+       ABORT(r);
+
+   if (params->realm && params->nonce) {
+       if ((r=nr_stun_message_add_realm_attribute(req, params->realm)))
+           ABORT(r);
+
+       if ((r=nr_stun_message_add_nonce_attribute(req, params->nonce)))
+           ABORT(r);
+
+       if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password)))
+           ABORT(r);
+   }
+
+   *msg = req;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&req);
+   return _status;
+}
+
+int
+nr_stun_build_req_st_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *req = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_username_attribute(req, params->username)))
+       ABORT(r);
+
+   if (params->password) {
+       if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password)))
+           ABORT(r);
+   }
+
+   *msg = req;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&req);
+   return _status;
+}
+
+int
+nr_stun_build_req_no_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *req = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
+       ABORT(r);
+
+   *msg = req;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&req);
+   return _status;
+}
+
+int
+nr_stun_build_keepalive(nr_stun_client_stun_keepalive_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *ind = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_INDICATION, &ind)))
+       ABORT(r);
+
+   *msg = ind;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&ind);
+   return _status;
+}
+
+#ifdef USE_STUND_0_96
+int
+nr_stun_build_req_stund_0_96(nr_stun_client_stun_binding_request_stund_0_96_params *params, nr_stun_message **msg)
+{
+    int r,_status;
+    nr_stun_message *req = 0;
+
+    if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUND_0_96, NR_STUN_MSG_BINDING_REQUEST, &req)))
+        ABORT(r);
+
+    if ((r=nr_stun_message_add_change_request_attribute(req, 0)))
+        ABORT(r);
+
+    assert(! nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME, 0));
+    assert(! nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0));
+
+    *msg = req;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&req);
+   return _status;
+}
+#endif /* USE_STUND_0_96 */
+
+#ifdef USE_ICE
+int
+nr_stun_build_use_candidate(nr_stun_client_ice_use_candidate_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *req = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_username_attribute(req, params->username)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_message_integrity_attribute(req, &params->password)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_use_candidate_attribute(req)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_priority_attribute(req, params->priority)))
+       ABORT(r);
+
+   *msg = req;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&req);
+   return _status;
+}
+
+int
+nr_stun_build_req_ice(nr_stun_client_ice_binding_request_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *req = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_username_attribute(req, params->username)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_message_integrity_attribute(req, &params->password)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_priority_attribute(req, params->priority)))
+       ABORT(r);
+
+   switch (params->control) {
+   case NR_ICE_CONTROLLING:
+       if ((r=nr_stun_message_add_ice_controlling_attribute(req, params->tiebreaker)))
+           ABORT(r);
+       break;
+   case NR_ICE_CONTROLLED:
+       if ((r=nr_stun_message_add_ice_controlled_attribute(req, params->tiebreaker)))
+           ABORT(r);
+       break;
+   }
+
+   *msg = req;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&req);
+   return _status;
+}
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+int
+nr_stun_build_allocate_request1(nr_stun_client_allocate_request1_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *req = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_ALLOCATE_REQUEST, &req)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_username_attribute(req, params->username)))
+       ABORT(r);
+
+   *msg = req;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&req);
+   return _status;
+}
+
+int
+nr_stun_build_allocate_request2(nr_stun_client_allocate_request2_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *req = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_ALLOCATE_REQUEST, &req)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_username_attribute(req, params->username)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_realm_attribute(req, params->realm)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_nonce_attribute(req, params->nonce)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_bandwidth_attribute(req, params->bandwidth_kbps)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs)))
+       ABORT(r);
+
+   *msg = req;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&req);
+   return _status;
+}
+
+int
+nr_stun_build_send_indication(nr_stun_client_send_indication_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *ind = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_SEND_INDICATION, &ind)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_remote_address_attribute(ind, &params->remote_addr)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_data_attribute(ind, params->data.data, params->data.len)))
+       ABORT(r);
+
+   *msg = ind;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&ind);
+   return _status;
+}
+
+int
+nr_stun_build_set_active_dest_request(nr_stun_client_set_active_dest_request_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *req = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_SET_ACTIVE_DEST_REQUEST, &req)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_remote_address_attribute(req, &params->remote_addr)))
+       ABORT(r);
+
+   *msg = req;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&req);
+   return _status;
+}
+
+int
+nr_stun_build_data_indication(nr_stun_client_data_indication_params *params, nr_stun_message **msg)
+{
+   int r,_status;
+   nr_stun_message *ind = 0;
+
+   if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_DATA_INDICATION, &ind)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_remote_address_attribute(ind, &params->remote_addr)))
+       ABORT(r);
+
+   if ((r=nr_stun_message_add_data_attribute(ind, params->data.data, params->data.len)))
+       ABORT(r);
+
+   *msg = ind;
+
+   _status=0;
+ abort:
+   if (_status) nr_stun_message_destroy(&ind);
+   return _status;
+}
+
+#endif /* USE_TURN */
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1.1 */
+int
+nr_stun_form_success_response(nr_stun_message *req, nr_transport_addr *from, Data *password, nr_stun_message *res)
+{
+    int r,_status;
+    int request_method;
+    char server_name[NR_STUN_MAX_SERVER_BYTES+1]; /* +1 for \0 */
+
+    /* set up information for default response */
+
+    request_method = NR_STUN_GET_TYPE_METHOD(req->header.type);
+    res->header.type = NR_STUN_TYPE(request_method, NR_CLASS_RESPONSE);
+    res->header.magic_cookie = req->header.magic_cookie;
+    memcpy(&res->header.id, &req->header.id, sizeof(res->header.id));
+
+    r_log(NR_LOG_STUN, LOG_DEBUG, "Mapped Address = %s", from->as_string);
+
+    if ((r=nr_stun_message_add_xor_mapped_address_attribute(res, from)))
+        ABORT(r);
+
+    if (!NR_reg_get_string(NR_STUN_REG_PREF_SERVER_NAME, server_name, sizeof(server_name))) {
+        if ((r=nr_stun_message_add_server_attribute(res, server_name)))
+            ABORT(r);
+    }
+
+    if (res->header.magic_cookie == NR_STUN_MAGIC_COOKIE) {
+        if (password != 0) {
+            if ((r=nr_stun_message_add_message_integrity_attribute(res, password)))
+                ABORT(r);
+        }
+
+        if ((r=nr_stun_message_add_fingerprint_attribute(res)))
+            ABORT(r);
+    }
+
+    _status=0;
+ abort:
+    return _status;
+}
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1.1 */
+void
+nr_stun_form_error_response(nr_stun_message *req, nr_stun_message* res, int number, char* msg)
+{
+    char *str;
+    int request_method;
+    char server_name[NR_STUN_MAX_SERVER_BYTES+1]; /* +1 for \0 */
+
+    if (number < 300 || number > 699)
+        number = 500;
+
+    r_log(NR_LOG_STUN, LOG_DEBUG, "Responding with error %d: %s", number, msg);
+
+    request_method = NR_STUN_GET_TYPE_METHOD(req->header.type);
+    res->header.type = NR_STUN_TYPE(request_method, NR_CLASS_ERROR_RESPONSE);
+    res->header.magic_cookie = req->header.magic_cookie;
+    memcpy(&res->header.id, &req->header.id, sizeof(res->header.id));
+
+    /* during development we should never see 500s (hopefully not in deployment either) */
+    assert(number != 500);
+
+    str = 0;
+    switch (number) {
+    case 300:  str = "Try Alternate";       break;
+    case 400:  str = "Bad Request";         break;
+    case 401:  str = "Unauthorized";        break;
+    case 420:  str = "Unknown Attribute";   break;
+    case 438:  str = "Stale Nonce";         break;
+#ifdef USE_ICE
+    case 487:  str = "Role Conflict";       break;
+#endif
+    case 500:  str = "Server Error";        break;
+    }
+    if (str == 0) {
+        assert(0);  /* should never happen */
+        str = "Unknown";
+    }
+
+    if (nr_stun_message_add_error_code_attribute(res, number, str)) {
+         assert(0);  /* should never happen */
+    }
+
+    if (!NR_reg_get_string(NR_STUN_REG_PREF_SERVER_NAME, server_name, sizeof(server_name))) {
+        nr_stun_message_add_server_attribute(res, server_name);
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_build.h
@@ -0,0 +1,148 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef _stun_build_h
+#define _stun_build_h
+
+#include "stun.h"
+
+#define NR_STUN_MODE_STUN               1
+#ifdef USE_STUND_0_96
+#define NR_STUN_MODE_STUND_0_96         2    /* backwards compatibility mode */
+#endif /* USE_STUND_0_96 */
+int nr_stun_form_request_or_indication(int mode, int msg_type, nr_stun_message **msg);
+
+typedef struct nr_stun_client_stun_binding_request_params_ {
+    char *username;
+    Data *password;
+    char *nonce;
+    char *realm;
+} nr_stun_client_stun_binding_request_params;
+
+int nr_stun_build_req_lt_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg);
+int nr_stun_build_req_st_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg);
+int nr_stun_build_req_no_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg);
+
+
+typedef struct nr_stun_client_stun_keepalive_params_ {
+#ifdef WIN32  // silly VC++ gives error if no members
+    int dummy;
+#endif
+} nr_stun_client_stun_keepalive_params;
+
+int nr_stun_build_keepalive(nr_stun_client_stun_keepalive_params *params, nr_stun_message **msg);
+
+
+#ifdef USE_STUND_0_96
+typedef struct nr_stun_client_stun_binding_request_stund_0_96_params_ {
+#ifdef WIN32  // silly VC++ gives error if no members
+    int dummy;
+#endif
+} nr_stun_client_stun_binding_request_stund_0_96_params;
+
+int nr_stun_build_req_stund_0_96(nr_stun_client_stun_binding_request_stund_0_96_params *params, nr_stun_message **msg);
+#endif /* USE_STUND_0_96 */
+
+
+#ifdef USE_ICE
+typedef struct nr_stun_client_ice_use_candidate_params_ {
+    char *username;
+    Data password;
+    UINT4 priority;
+} nr_stun_client_ice_use_candidate_params;
+
+int nr_stun_build_use_candidate(nr_stun_client_ice_use_candidate_params *params, nr_stun_message **msg);
+
+
+typedef struct nr_stun_client_ice_binding_request_params_ {
+    char *username;
+    Data password;
+    UINT4 priority;
+    int control;
+#define NR_ICE_CONTROLLING  1
+#define NR_ICE_CONTROLLED   2
+    UINT8 tiebreaker;
+} nr_stun_client_ice_binding_request_params;
+
+int nr_stun_build_req_ice(nr_stun_client_ice_binding_request_params *params, nr_stun_message **msg);
+#endif /* USE_ICE */
+
+
+#ifdef USE_TURN
+typedef struct nr_stun_client_allocate_request1_params_ {
+    char *username;
+} nr_stun_client_allocate_request1_params;
+
+int nr_stun_build_allocate_request1(nr_stun_client_allocate_request1_params *params, nr_stun_message **msg);
+
+
+typedef struct nr_stun_client_allocate_request2_params_ {
+    char *username;
+    char *realm;
+    char *nonce;
+    Data *password;
+    UINT4 bandwidth_kbps;
+    UINT4 lifetime_secs;
+} nr_stun_client_allocate_request2_params;
+
+int nr_stun_build_allocate_request2(nr_stun_client_allocate_request2_params *params, nr_stun_message **msg);
+
+
+typedef struct nr_stun_client_send_indication_params_ {
+    nr_transport_addr remote_addr;
+    Data data;
+} nr_stun_client_send_indication_params;
+
+int nr_stun_build_send_indication(nr_stun_client_send_indication_params *params, nr_stun_message **msg);
+
+
+typedef struct nr_stun_client_set_active_dest_request_params_ {
+    nr_transport_addr remote_addr;
+    Data *password;
+} nr_stun_client_set_active_dest_request_params;
+
+int nr_stun_build_set_active_dest_request(nr_stun_client_set_active_dest_request_params *params, nr_stun_message **msg);
+
+
+typedef struct nr_stun_client_data_indication_params_ {
+    nr_transport_addr remote_addr;
+    Data data;
+} nr_stun_client_data_indication_params;
+
+int nr_stun_build_data_indication(nr_stun_client_data_indication_params *params, nr_stun_message **msg);
+#endif /* USE_TURN */
+
+int nr_stun_form_success_response(nr_stun_message *req, nr_transport_addr *from, Data *password, nr_stun_message *res);
+void nr_stun_form_error_response(nr_stun_message *request, nr_stun_message* response, int number, char* msg);
+
+#endif
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_client_ctx.c
@@ -0,0 +1,689 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems, Network Resonance nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+
+static char *RCSSTRING __UNUSED__="$Id: stun_client_ctx.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
+
+#include <assert.h>
+#include <string.h>
+
+#include <nr_api.h>
+#include "stun.h"
+#include "async_timer.h"
+#include "registry.h"
+#include "stun_reg.h"
+#include "r_time.h"
+
+static int nr_stun_client_send_request(nr_stun_client_ctx *ctx);
+static void nr_stun_client_timer_expired_cb(NR_SOCKET s, int b, void *cb_arg);
+static int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password);
+
+int nr_stun_client_ctx_create(char *label, nr_socket *sock, nr_transport_addr *peer, UINT4 RTO, nr_stun_client_ctx **ctxp)
+  {
+    nr_stun_client_ctx *ctx=0;
+    int r,_status;
+
+    if ((r=nr_stun_startup()))
+      ABORT(r);
+
+    if(!(ctx=RCALLOC(sizeof(nr_stun_client_ctx))))
+      ABORT(R_NO_MEMORY);
+
+    ctx->state=NR_STUN_CLIENT_STATE_INITTED;
+
+    if(!(ctx->label=r_strdup(label)))
+      ABORT(R_NO_MEMORY);
+
+    ctx->sock=sock;
+
+    nr_socket_getaddr(sock,&ctx->my_addr);
+    nr_transport_addr_copy(&ctx->peer_addr,peer);
+
+    if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_RETRANSMIT_TIMEOUT, &ctx->rto_ms)) {
+        if (RTO != 0)
+            ctx->rto_ms = RTO;
+        else
+            ctx->rto_ms = 100;
+    }
+
+    if (NR_reg_get_double(NR_STUN_REG_PREF_CLNT_RETRANSMIT_BACKOFF, &ctx->retransmission_backoff_factor))
+        ctx->retransmission_backoff_factor = 2.0;
+
+    if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_MAXIMUM_TRANSMITS, &ctx->maximum_transmits))
+        ctx->maximum_transmits = 7;
+
+    if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF, &ctx->final_retransmit_backoff_ms))
+        ctx->final_retransmit_backoff_ms = 16 * ctx->rto_ms;
+
+    *ctxp=ctx;
+
+    _status=0;
+  abort:
+    if(_status){
+      nr_stun_client_ctx_destroy(&ctx);
+    }
+    return(_status);
+  }
+
+int nr_stun_client_start(nr_stun_client_ctx *ctx, int mode, NR_async_cb finished_cb, void *cb_arg)
+  {
+    int r,_status;
+
+    if (ctx->state != NR_STUN_CLIENT_STATE_INITTED)
+        ABORT(R_NOT_PERMITTED);
+    
+    ctx->mode=mode;
+
+    ctx->state=NR_STUN_CLIENT_STATE_RUNNING;
+    ctx->finished_cb=finished_cb;
+    ctx->cb_arg=cb_arg;
+
+    if(mode!=NR_STUN_CLIENT_MODE_KEEPALIVE){
+      if(r=nr_stun_client_send_request(ctx))
+        ABORT(r);
+    }
+
+    _status=0;
+  abort:
+   if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) {
+        ctx->finished_cb = 0;  /* prevent 2nd call */
+        /* finished_cb call must be absolutely last thing in function
+         * because as a side effect this ctx may be operated on in the
+         * callback */
+        finished_cb(0,0,cb_arg);
+    }
+
+    return(_status);
+  }
+
+int nr_stun_client_restart(nr_stun_client_ctx *ctx)
+  {
+    int r,_status;
+    int mode;
+    NR_async_cb finished_cb;
+    void *cb_arg;
+    nr_stun_message_attribute *ec;
+    nr_stun_message_attribute *as;
+
+    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
+        ABORT(R_NOT_PERMITTED);
+ 
+    assert(ctx->retry_ct <= 2);
+    if (ctx->retry_ct > 2)
+        ABORT(R_NOT_PERMITTED);
+
+    ++ctx->retry_ct;
+
+    mode = ctx->mode;
+    finished_cb = ctx->finished_cb;
+    cb_arg = ctx->cb_arg;
+
+    if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_ERROR_CODE, &ec)
+     && ec->u.error_code.number == 300) {
+        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_ALTERNATE_SERVER, &as)) {
+            nr_transport_addr_copy(&ctx->peer_addr, &as->u.alternate_server);
+        }
+    }
+
+    nr_stun_client_reset(ctx);
+
+    if (r=nr_stun_client_start(ctx, mode, finished_cb, cb_arg))
+      ABORT(r);
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int
+nr_stun_client_reset(nr_stun_client_ctx *ctx)
+{
+    /* Cancel the timer firing */
+    if (ctx->timer_handle){
+        NR_async_timer_cancel(ctx->timer_handle);
+        ctx->timer_handle=0;
+    }
+
+    nr_stun_message_destroy(&ctx->request);
+    ctx->request   = 0;
+
+    nr_stun_message_destroy(&ctx->response);
+    ctx->response  = 0;
+
+    memset(&ctx->results, 0, sizeof(ctx->results));
+
+    ctx->mode          = 0;
+    ctx->finished_cb   = 0;
+    ctx->cb_arg        = 0;
+    ctx->request_ct    = 0;
+    ctx->timeout_ms    = 0;
+
+    ctx->state = NR_STUN_CLIENT_STATE_INITTED;
+
+    return 0;
+}
+
+static void nr_stun_client_timer_expired_cb(NR_SOCKET s, int b, void *cb_arg)
+  {
+    int _status;
+    nr_stun_client_ctx *ctx=cb_arg;
+    struct timeval now;
+    INT8 ms_waited;
+
+    /* Prevent this timer from being cancelled later */
+    ctx->timer_handle=0;
+
+    /* Shouldn't happen */
+    if(ctx->state==NR_STUN_CLIENT_STATE_CANCELLED)
+      ABORT(R_REJECTED);
+
+    gettimeofday(&now, 0);
+    if (r_timeval_diff_ms(&now, &ctx->timer_set, &ms_waited)) {
+        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired",ctx->label);
+    }
+    else {
+        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired (after %llu ms)",ctx->label, ms_waited);
+    }
+
+    if (ctx->request_ct >= ctx->maximum_transmits) {
+        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timed out",ctx->label);
+        ctx->state=NR_STUN_CLIENT_STATE_TIMED_OUT;
+        ABORT(R_FAILED);
+    }
+
+    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
+        ABORT(R_NOT_PERMITTED);
+
+    /* as a side effect will reset the timer */
+    nr_stun_client_send_request(ctx);
+
+    _status = 0;
+  abort:
+    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) {
+        /* Cancel the timer firing */
+        if (ctx->timer_handle){
+            NR_async_timer_cancel(ctx->timer_handle);
+            ctx->timer_handle=0;
+        }
+
+        if (ctx->finished_cb) {
+            NR_async_cb finished_cb = ctx->finished_cb; 
+            ctx->finished_cb = 0;  /* prevent 2nd call */
+            /* finished_cb call must be absolutely last thing in function
+             * because as a side effect this ctx may be operated on in the
+             * callback */
+            finished_cb(0,0,ctx->cb_arg);
+        }
+    }
+    return;
+  }
+
+int nr_stun_client_force_retransmit(nr_stun_client_ctx *ctx)
+  {
+    int r,_status;
+
+    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
+        ABORT(R_NOT_PERMITTED);
+
+    if (ctx->request_ct > ctx->maximum_transmits) {
+        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Too many retransmit attempts",ctx->label);
+        ABORT(R_FAILED);
+    }
+
+    /* if there is a scheduled retransimt, get rid of the scheduled retransmit
+     * and retransmit immediately */
+    if (ctx->timer_handle) {
+        NR_async_timer_cancel(ctx->timer_handle);
+        ctx->timer_handle=0;
+
+        if (r=nr_stun_client_send_request(ctx))
+            ABORT(r);
+    }
+
+    _status=0;
+  abort:
+
+    return(_status);
+  }
+
+static int nr_stun_client_send_request(nr_stun_client_ctx *ctx)
+  {
+    int r,_status;
+    char string[256];
+
+    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
+        ABORT(R_NOT_PERMITTED);
+
+    r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Sending(my_addr=%s,peer_addr=%s)",ctx->label,ctx->my_addr.as_string,ctx->peer_addr.as_string);
+
+    if (ctx->request == 0) {
+        switch (ctx->mode) {
+        case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
+            ctx->params.stun_binding_request.nonce = ctx->nonce;
+            ctx->params.stun_binding_request.realm = ctx->realm;
+            if ((r=nr_stun_build_req_lt_auth(&ctx->params.stun_binding_request, &ctx->request)))
+                ABORT(r);
+            break;
+        case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
+            if ((r=nr_stun_build_req_st_auth(&ctx->params.stun_binding_request, &ctx->request)))
+                ABORT(r);
+            break;
+        case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
+            if ((r=nr_stun_build_req_no_auth(&ctx->params.stun_binding_request, &ctx->request)))
+                ABORT(r);
+            break;
+        case NR_STUN_CLIENT_MODE_KEEPALIVE:
+            if ((r=nr_stun_build_keepalive(&ctx->params.stun_keepalive, &ctx->request)))
+                ABORT(r);
+            break;
+#ifdef USE_STUND_0_96
+        case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
+            if ((r=nr_stun_build_req_stund_0_96(&ctx->params.stun_binding_request_stund_0_96, &ctx->request)))
+                ABORT(r);
+            break;
+#endif /* USE_STUND_0_96 */
+
+#ifdef USE_ICE
+        case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
+            if ((r=nr_stun_build_use_candidate(&ctx->params.ice_use_candidate, &ctx->request)))
+                ABORT(r);
+            break;
+        case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
+            if ((r=nr_stun_build_req_ice(&ctx->params.ice_binding_request, &ctx->request)))
+                ABORT(r);
+            break;
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+        case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST1:
+            if ((r=nr_stun_build_allocate_request1(&ctx->params.allocate_request1, &ctx->request)))
+                ABORT(r);
+            break;
+        case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST2:
+            if ((r=nr_stun_build_allocate_request2(&ctx->params.allocate_request2, &ctx->request)))
+                ABORT(r);
+            break;
+        case NR_TURN_CLIENT_MODE_SEND_INDICATION:
+            if ((r=nr_stun_build_send_indication(&ctx->params.send_indication, &ctx->request)))
+                ABORT(r);
+            break;
+        case NR_TURN_CLIENT_MODE_SET_ACTIVE_DEST_REQUEST:
+            if ((r=nr_stun_build_set_active_dest_request(&ctx->params.set_active_dest_request, &ctx->request)))
+                ABORT(r);
+            break;
+        case NR_TURN_CLIENT_MODE_DATA_INDICATION:
+            if ((r=nr_stun_build_data_indication(&ctx->params.data_indication, &ctx->request)))
+                ABORT(r);
+            break;
+#endif /* USE_TURN */
+
+        default:
+            assert(0);
+            ABORT(R_FAILED);
+            break;
+        }
+    }
+
+    if (ctx->request->length == 0) {
+        if ((r=nr_stun_encode_message(ctx->request)))
+            ABORT(r);
+    }
+
+    snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Sending to %s ", ctx->label, ctx->peer_addr.as_string);
+    r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)ctx->request->buffer, ctx->request->length);
+
+    if(r=nr_socket_sendto(ctx->sock, ctx->request->buffer, ctx->request->length, 0, &ctx->peer_addr))
+      ABORT(r);
+    
+    ctx->request_ct++;
+
+    if (NR_STUN_GET_TYPE_CLASS(ctx->request->header.type) == NR_CLASS_INDICATION) {
+        /* no need to set the timer because indications don't receive a
+         * response */
+    }
+    else {
+        if (ctx->request_ct < ctx->maximum_transmits) {
+            ctx->timeout_ms *= ctx->retransmission_backoff_factor;
+            ctx->timeout_ms += ctx->rto_ms;
+        }
+        else {
+            ctx->timeout_ms += ctx->final_retransmit_backoff_ms;
+        }
+
+        r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Next timer will fire in %u ms",ctx->label, ctx->timeout_ms);
+
+        gettimeofday(&ctx->timer_set, 0);
+
+        NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle);
+    }
+   
+    _status=0;
+  abort:
+    if (_status) {
+      ctx->state=NR_STUN_CLIENT_STATE_FAILED;
+    }
+    return(_status);
+  }
+
+static int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password)
+{
+    *password = (Data*)arg;
+    if (!arg)
+        return(R_NOT_FOUND);
+    return(0);
+}
+
+int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr)
+  {
+    int r,_status;
+    char string[256];
+    Data *password = 0;
+    nr_stun_message_attribute *attr;
+    nr_transport_addr *mapped_addr = 0;
+
+    if(ctx->state==NR_STUN_CLIENT_STATE_CANCELLED)
+      ABORT(R_REJECTED);
+
+    if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
+      ABORT(R_REJECTED);
+
+    r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received(my_addr=%s,peer_addr=%s)",ctx->label,ctx->my_addr.as_string,peer_addr->as_string);
+
+    snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Received ", ctx->label);
+    r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)msg, len);
+
+    /* determine password */
+    switch (ctx->mode) {
+    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
+    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
+        password = ctx->params.stun_binding_request.password;
+        break;
+
+    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
+        /* do nothing */
+        break;
+
+    case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
+        /* do nothing */
+        break;
+
+#ifdef USE_ICE
+    case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
+        password = &ctx->params.ice_binding_request.password;
+        break;
+    case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
+        password = &ctx->params.ice_binding_request.password;
+        break;
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST1:
+        /* do nothing */
+        break;
+    case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST2:
+        /* do nothing */
+        break;
+    case NR_TURN_CLIENT_MODE_SET_ACTIVE_DEST_REQUEST:
+        /* do nothing */
+        break;
+    case NR_TURN_CLIENT_MODE_SEND_INDICATION:
+        /* do nothing -- we just got our DATA-INDICATION */
+        break;
+#endif /* USE_TURN */
+
+    default:
+        assert(0);
+        ABORT(R_FAILED);
+        break;
+    }
+
+#ifdef USE_TURN
+    if (ctx->mode == NR_TURN_CLIENT_MODE_SEND_INDICATION) {
+        /* SEND-INDICATION gets a DATA-INDICATION back, which will always
+         * be a different transaction, so don't perform the check in that
+         * case */
+    }
+#endif /* USE_TURN */
+
+    if ((r=nr_stun_message_create2(&ctx->response, msg, len)))
+        ABORT(r);
+
+    if ((r=nr_stun_decode_message(ctx->response, nr_stun_client_get_password, password)))
+        ABORT(r);
+
+    if ((r=nr_stun_receive_message(ctx->request, ctx->response)))
+        ABORT(r);
+
+/* TODO: !nn! currently using password!=0 to mean that auth is required,
+ * TODO: !nn! but we should probably pass that in explicitly via the
+ * TODO: !nn! usage (ctx->mode?) */
+    if (password) {
+        if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_NONCE, 0)) {
+            if ((r=nr_stun_receive_response_long_term_auth(ctx->response, ctx)))
+                ABORT(r);
+        }
+        else {
+            if ((r=nr_stun_receive_response_short_term_auth(ctx->response)))
+                ABORT(r);
+        }
+    }
+
+    if (NR_STUN_GET_TYPE_CLASS(ctx->response->header.type) == NR_CLASS_RESPONSE) {
+        if ((r=nr_stun_process_success_response(ctx->response)))
+            ABORT(r);
+    }
+    else {
+        if ((r=nr_stun_process_error_response(ctx->response))) {