summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/transport/third_party/nICEr/src/stun
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webrtc/transport/third_party/nICEr/src/stun')
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-bsd.c110
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-bsd.h13
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-netlink.c285
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-netlink.h45
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-win32.c210
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-win32.h13
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs.c176
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs.h43
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c656
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_buffered_stun.h66
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_turn.c195
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_turn.h48
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun.h218
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_build.c611
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_build.h147
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_client_ctx.c888
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_client_ctx.h200
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.c1550
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.h78
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_hint.c245
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_hint.h44
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_msg.c364
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_msg.h208
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_proc.c554
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_proc.h53
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_reg.h58
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_server_ctx.c468
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_server_ctx.h80
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_util.c352
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_util.h62
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/turn_client_ctx.c1277
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/stun/turn_client_ctx.h161
32 files changed, 9478 insertions, 0 deletions
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-bsd.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-bsd.c
new file mode 100644
index 0000000000..ec2d084445
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-bsd.c
@@ -0,0 +1,110 @@
+/* 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/. */
+
+#if defined(BSD) || defined(DARWIN)
+#include "addrs-bsd.h"
+#include <csi_platform.h>
+#include <assert.h>
+#include <string.h>
+#include "util.h"
+#include "stun_util.h"
+#include "util.h"
+#include <r_macros.h>
+
+#include <sys/types.h> /* getifaddrs */
+#include <ifaddrs.h> /* getifaddrs */
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet6/in6_var.h>
+
+static int
+stun_ifaddr_get_v6_flags(struct ifaddrs *ifaddr)
+{
+ if (ifaddr->ifa_addr->sa_family != AF_INET6) {
+ return 0;
+ }
+
+ int flags = 0;
+ int s = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (!s) {
+ r_log(NR_LOG_STUN, LOG_ERR, "socket(AF_INET6, SOCK_DGRAM, 0) failed, errno=%d", errno);
+ assert(0);
+ return 0;
+ }
+ struct in6_ifreq ifr6;
+ memset(&ifr6, 0, sizeof(ifr6));
+ strncpy(ifr6.ifr_name, ifaddr->ifa_name, sizeof(ifr6.ifr_name));
+ /* ifr_addr is a sockaddr_in6, ifa_addr is a sockaddr* */
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)ifaddr->ifa_addr;
+ ifr6.ifr_addr = *sin6;
+ if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) != -1) {
+ flags = ifr6.ifr_ifru.ifru_flags6;
+ } else {
+ r_log(NR_LOG_STUN, LOG_ERR, "ioctl(SIOCGIFAFLAG_IN6) failed, errno=%d", errno);
+ assert(0);
+ }
+ close(s);
+ return flags;
+}
+
+static int
+stun_ifaddr_is_disallowed_v6(int flags) {
+ return flags & (IN6_IFF_ANYCAST | IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED);
+}
+
+int stun_getaddrs_filtered(nr_local_addr addrs[], int maxaddrs, int *count)
+{
+ int r,_status,flags;
+ struct ifaddrs* if_addrs_head=NULL;
+ struct ifaddrs* if_addr;
+
+ *count = 0;
+
+ if (maxaddrs <= 0)
+ ABORT(R_BAD_ARGS);
+
+ if (getifaddrs(&if_addrs_head) == -1) {
+ r_log(NR_LOG_STUN, LOG_ERR, "getifaddrs error e = %d", errno);
+ ABORT(R_INTERNAL);
+ }
+
+ if_addr = if_addrs_head;
+
+ while (if_addr && *count < maxaddrs) {
+ /* This can be null */
+ if (if_addr->ifa_addr) {
+ switch (if_addr->ifa_addr->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ flags = stun_ifaddr_get_v6_flags(if_addr);
+ if (!stun_ifaddr_is_disallowed_v6(flags)) {
+ if (r=nr_sockaddr_to_transport_addr(if_addr->ifa_addr, IPPROTO_UDP, 0, &(addrs[*count].addr))) {
+ r_log(NR_LOG_STUN, LOG_ERR, "nr_sockaddr_to_transport_addr error r = %d", r);
+ } else {
+ if (flags & IN6_IFF_TEMPORARY) {
+ addrs[*count].flags |= NR_ADDR_FLAG_TEMPORARY;
+ }
+ (void)strlcpy(addrs[*count].addr.ifname, if_addr->ifa_name, sizeof(addrs[*count].addr.ifname));
+ ++(*count);
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ if_addr = if_addr->ifa_next;
+ }
+
+ _status=0;
+abort:
+ if (if_addrs_head) {
+ freeifaddrs(if_addrs_head);
+ }
+ return(_status);
+}
+#endif
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-bsd.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-bsd.h
new file mode 100644
index 0000000000..b575586f48
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-bsd.h
@@ -0,0 +1,13 @@
+/* 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/. */
+
+#ifndef STUN_IFADDRS_BSD_H_
+#define STUN_IFADDRS_BSD_H_
+
+#include "local_addr.h"
+
+int stun_getaddrs_filtered(nr_local_addr addrs[], int maxaddrs, int *count);
+
+#endif /* STUN_IFADDRS_BSD_H_ */
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-netlink.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-netlink.c
new file mode 100644
index 0000000000..8d22e5979e
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-netlink.c
@@ -0,0 +1,285 @@
+/*
+Copyright (c) 2011, The WebRTC project authors. 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 Google 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
+HOLDER 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.
+*/
+
+#if defined(LINUX)
+#include <net/if.h>
+#include "addrs-netlink.h"
+#include <csi_platform.h>
+#include <assert.h>
+#include <string.h>
+#include "util.h"
+#include "stun_util.h"
+#include "util.h"
+#include <r_macros.h>
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <errno.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#ifdef ANDROID
+/* Work around an Android NDK < r8c bug */
+#undef __unused
+#else
+#include <linux/if.h> /* struct ifreq, IFF_POINTTOPOINT */
+#include <linux/wireless.h> /* struct iwreq */
+#include <linux/ethtool.h> /* struct ethtool_cmd */
+#include <linux/sockios.h> /* SIOCETHTOOL */
+#endif /* ANDROID */
+
+
+struct netlinkrequest {
+ struct nlmsghdr header;
+ struct ifaddrmsg msg;
+};
+
+static const int kMaxReadSize = 4096;
+
+static void set_ifname(nr_local_addr *addr, struct ifaddrmsg* msg) {
+ assert(sizeof(addr->addr.ifname) > IF_NAMESIZE);
+ if_indextoname(msg->ifa_index, addr->addr.ifname);
+}
+
+static int get_siocgifflags(nr_local_addr *addr) {
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1) {
+ assert(0);
+ return 0;
+ }
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, addr->addr.ifname, IFNAMSIZ - 1);
+ int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
+ close(fd);
+ if (rc == -1) {
+ assert(0);
+ return 0;
+ }
+ return ifr.ifr_flags;
+}
+
+static int set_sockaddr(nr_local_addr *addr, struct ifaddrmsg* msg, struct rtattr* rta) {
+ assert(rta->rta_type == IFA_ADDRESS || rta->rta_type == IFA_LOCAL);
+ void *data = RTA_DATA(rta);
+ size_t len = RTA_PAYLOAD(rta);
+ if (msg->ifa_family == AF_INET) {
+ struct sockaddr_in sa;
+ memset(&sa, 0, sizeof(struct sockaddr_in));
+ sa.sin_family = AF_INET;
+ memcpy(&sa.sin_addr, data, len);
+ return nr_sockaddr_to_transport_addr((struct sockaddr*)&sa, IPPROTO_UDP, 0, &(addr->addr));
+ } else if (msg->ifa_family == AF_INET6) {
+ struct sockaddr_in6 sa;
+ memset(&sa, 0, sizeof(struct sockaddr_in6));
+ sa.sin6_family = AF_INET6;
+ /* We do not set sin6_scope_id to ifa_index, because that is only valid for
+ * link local addresses, and we don't use those anyway */
+ memcpy(&sa.sin6_addr, data, len);
+ return nr_sockaddr_to_transport_addr((struct sockaddr*)&sa, IPPROTO_UDP, 0, &(addr->addr));
+ }
+
+ return R_BAD_ARGS;
+}
+
+static int
+stun_ifaddr_is_disallowed_v6(int flags) {
+ return flags & (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC | IFA_F_DADFAILED | IFA_F_DEPRECATED);
+}
+
+static int
+stun_convert_netlink(nr_local_addr *addr, struct ifaddrmsg *address_msg, struct rtattr* rta)
+{
+ int r = set_sockaddr(addr, address_msg, rta);
+ if (r) {
+ r_log(NR_LOG_STUN, LOG_ERR, "set_sockaddr error r = %d", r);
+ return r;
+ }
+
+ set_ifname(addr, address_msg);
+
+ if (address_msg->ifa_flags & IFA_F_TEMPORARY) {
+ addr->flags |= NR_ADDR_FLAG_TEMPORARY;
+ }
+
+ int flags = get_siocgifflags(addr);
+ if (flags & IFF_POINTOPOINT)
+ {
+ addr->interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
+ /* TODO (Bug 896913): find backend network type of this VPN */
+ }
+
+#if defined(LINUX) && !defined(ANDROID)
+ struct ethtool_cmd ecmd;
+ struct ifreq ifr;
+ struct iwreq wrq;
+ int e;
+ int s = socket(AF_INET, SOCK_DGRAM, 0);
+
+ strncpy(ifr.ifr_name, addr->addr.ifname, sizeof(ifr.ifr_name));
+ /* TODO (Bug 896851): interface property for Android */
+ /* Getting ethtool for ethernet information. */
+ ecmd.cmd = ETHTOOL_GSET;
+ /* In/out param */
+ ifr.ifr_data = (void*)&ecmd;
+
+ e = ioctl(s, SIOCETHTOOL, &ifr);
+ if (e == 0)
+ {
+ /* For wireless network, we won't get ethtool, it's a wired
+ * connection */
+ addr->interface.type = NR_INTERFACE_TYPE_WIRED;
+#ifdef DONT_HAVE_ETHTOOL_SPEED_HI
+ addr->interface.estimated_speed = ecmd.speed;
+#else
+ addr->interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
+#endif
+ }
+
+ strncpy(wrq.ifr_name, addr->addr.ifname, sizeof(wrq.ifr_name));
+ e = ioctl(s, SIOCGIWRATE, &wrq);
+ if (e == 0)
+ {
+ addr->interface.type = NR_INTERFACE_TYPE_WIFI;
+ addr->interface.estimated_speed = wrq.u.bitrate.value / 1000;
+ }
+
+ close(s);
+
+#else
+ addr->interface.type = NR_INTERFACE_TYPE_UNKNOWN;
+ addr->interface.estimated_speed = 0;
+#endif
+ return 0;
+}
+
+int
+stun_getaddrs_filtered(nr_local_addr addrs[], int maxaddrs, int *count)
+{
+ int _status;
+ int fd = 0;
+
+ /* Scope everything else since we're using ABORT. */
+ {
+ *count = 0;
+
+ if (maxaddrs <= 0)
+ ABORT(R_BAD_ARGS);
+
+ fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (fd < 0) {
+ ABORT(R_INTERNAL);
+ }
+
+ struct netlinkrequest ifaddr_request;
+ memset(&ifaddr_request, 0, sizeof(ifaddr_request));
+ ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
+ ifaddr_request.header.nlmsg_type = RTM_GETADDR;
+ ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+
+ ssize_t bytes = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
+ if ((size_t)bytes != ifaddr_request.header.nlmsg_len) {
+ ABORT(R_INTERNAL);
+ }
+
+ char buf[kMaxReadSize];
+ ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
+ while ((amount_read > 0) && (*count != maxaddrs)) {
+ struct nlmsghdr* header = (struct nlmsghdr*)&buf[0];
+ size_t header_size = (size_t)amount_read;
+ for ( ; NLMSG_OK(header, header_size) && (*count != maxaddrs);
+ header = NLMSG_NEXT(header, header_size)) {
+ switch (header->nlmsg_type) {
+ case NLMSG_DONE:
+ /* Success. Return. */
+ close(fd);
+ return 0;
+ case NLMSG_ERROR:
+ ABORT(R_INTERNAL);
+ case RTM_NEWADDR: {
+ struct ifaddrmsg* address_msg =
+ (struct ifaddrmsg*)NLMSG_DATA(header);
+ struct rtattr* rta = IFA_RTA(address_msg);
+ ssize_t payload_len = IFA_PAYLOAD(header);
+ bool found = false;
+ while (RTA_OK(rta, payload_len)) {
+ // This is a bit convoluted. IFA_ADDRESS and IFA_LOCAL are the
+ // same thing except when using a POINTTOPOINT interface, in
+ // which case IFA_LOCAL is the local address, and IFA_ADDRESS is
+ // the remote address. In a reasonable world, that would mean we
+ // could just use IFA_LOCAL all the time. Sadly, IFA_LOCAL is not
+ // always set (IPv6 in particular). So, we have to be on the
+ // lookout for both, and prefer IFA_LOCAL when present.
+ if (rta->rta_type == IFA_ADDRESS || rta->rta_type == IFA_LOCAL) {
+ int family = address_msg->ifa_family;
+ if ((family == AF_INET || family == AF_INET6) &&
+ !stun_ifaddr_is_disallowed_v6(address_msg->ifa_flags) &&
+ !stun_convert_netlink(&addrs[*count], address_msg, rta)) {
+ found = true;
+ if (rta->rta_type == IFA_LOCAL) {
+ // IFA_LOCAL is what we really want; if we find it we're
+ // done. If this is IFA_ADDRESS instead, we do not proceed
+ // yet, and allow a subsequent IFA_LOCAL to overwrite what
+ // we just put in |addrs|.
+ break;
+ }
+ }
+ }
+ /* TODO: Use IFA_LABEL instead of if_indextoname? We would need
+ * to remember how many nr_local_addr we've converted for this
+ * ifaddrmsg, and set the label on all of them. */
+ rta = RTA_NEXT(rta, payload_len);
+ }
+
+ if (found) {
+ ++(*count);
+ }
+ break;
+ }
+ }
+ }
+ amount_read = recv(fd, &buf, kMaxReadSize, 0);
+ }
+ }
+
+ _status=0;
+abort:
+ close(fd);
+ return(_status);
+}
+
+#endif /* defined(LINUX) */
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-netlink.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-netlink.h
new file mode 100644
index 0000000000..b2b07bddc9
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-netlink.h
@@ -0,0 +1,45 @@
+/*
+Copyright (c) 2011, The WebRTC project authors. 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 Google 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
+HOLDER 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 WEBRTC_BASE_IFADDRS_NETLINK_H_
+#define WEBRTC_BASE_IFADDRS_NETLINK_H_
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include "local_addr.h"
+
+/* for platforms with netlink (android and linux) */
+/* Filters out things like deprecated addresses, and stuff that doesn't pass
+ * IPv6 duplicate address detection */
+int stun_getaddrs_filtered(nr_local_addr addrs[], int maxaddrs, int *count);
+#endif /* WEBRTC_BASE_IFADDRS_NETLINK_H_ */
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-win32.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-win32.c
new file mode 100644
index 0000000000..4fdf5e5d44
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-win32.c
@@ -0,0 +1,210 @@
+/* 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/. */
+
+#ifdef WIN32
+
+#include "addrs-win32.h"
+#include <csi_platform.h>
+#include <assert.h>
+#include <string.h>
+#include "util.h"
+#include "stun_util.h"
+#include "util.h"
+#include <r_macros.h>
+#include "nr_crypto.h"
+
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include <tchar.h>
+
+#define WIN32_MAX_NUM_INTERFACES 20
+
+#define NR_MD5_HASH_LENGTH 16
+
+#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
+ strlcpy(adapter_GUID_tchar, adapter_GUID, _NR_MAX_NAME_LENGTH);
+#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_win32_address_disallowed(IP_ADAPTER_UNICAST_ADDRESS *addr)
+{
+ return (addr->DadState != NldsPreferred) &&
+ (addr->DadState != IpDadStatePreferred);
+}
+
+static int stun_win32_address_temp_v6(IP_ADAPTER_UNICAST_ADDRESS *addr)
+{
+ return (addr->Address.lpSockaddr->sa_family == AF_INET6) &&
+ (addr->SuffixOrigin == IpSuffixOriginRandom);
+}
+
+int
+stun_getaddrs_filtered(nr_local_addr addrs[], int maxaddrs, int *count)
+{
+ int r, _status;
+ PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL, tmpAddress = NULL;
+ // recomended per https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
+ static const ULONG initialBufLen = 15000;
+ ULONG buflen = initialBufLen;
+ char bin_hashed_ifname[NR_MD5_HASH_LENGTH];
+ char hex_hashed_ifname[MAXIFNAME];
+ int n = 0;
+
+ *count = 0;
+
+ if (maxaddrs <= 0)
+ ABORT(R_BAD_ARGS);
+
+ /* According to MSDN (see above) we have try GetAdapterAddresses() multiple times */
+ for (n = 0; n < 5; n++) {
+ 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);
+ }
+
+ r = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, AdapterAddresses, &buflen);
+ if (r == NO_ERROR) {
+ break;
+ }
+ r_log(NR_LOG_STUN, LOG_ERR, "GetAdaptersAddresses() returned error (%d)", r);
+ RFREE(AdapterAddresses);
+ AdapterAddresses = NULL;
+ }
+
+ if (n >= 5) {
+ r_log(NR_LOG_STUN, LOG_ERR, "5 failures calling GetAdaptersAddresses()");
+ ABORT(R_INTERNAL);
+ }
+
+ n = 0;
+
+ /* Loop through the adapters */
+
+ for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) {
+
+ if (tmpAddress->OperStatus != IfOperStatusUp)
+ continue;
+
+ if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) {
+ IP_ADAPTER_UNICAST_ADDRESS *u = 0;
+
+ if(r=nr_crypto_md5((UCHAR *)tmpAddress->FriendlyName,
+ wcslen(tmpAddress->FriendlyName) * sizeof(wchar_t),
+ bin_hashed_ifname))
+ ABORT(r);
+ if(r=nr_bin2hex(bin_hashed_ifname, sizeof(bin_hashed_ifname),
+ hex_hashed_ifname))
+ ABORT(r);
+
+ 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)) {
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized sa_family for address on adapter %lu", tmpAddress->IfIndex);
+ continue;
+ }
+
+ if (stun_win32_address_disallowed(u)) {
+ continue;
+ }
+
+ if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, IPPROTO_UDP, 0, &(addrs[n].addr)))) {
+ ABORT(r);
+ }
+
+ strlcpy(addrs[n].addr.ifname, hex_hashed_ifname, sizeof(addrs[n].addr.ifname));
+ if (tmpAddress->IfType == IF_TYPE_ETHERNET_CSMACD) {
+ addrs[n].interface.type = NR_INTERFACE_TYPE_WIRED;
+ } else if (tmpAddress->IfType == IF_TYPE_IEEE80211) {
+ /* Note: this only works for >= Win Vista */
+ addrs[n].interface.type = NR_INTERFACE_TYPE_WIFI;
+ } else {
+ addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
+ }
+#if (_WIN32_WINNT >= 0x0600)
+ /* Note: only >= Vista provide link speed information */
+ addrs[n].interface.estimated_speed = tmpAddress->TransmitLinkSpeed / 1000;
+#else
+ addrs[n].interface.estimated_speed = 0;
+#endif
+ if (stun_win32_address_temp_v6(u)) {
+ addrs[n].flags |= NR_ADDR_FLAG_TEMPORARY;
+ }
+
+ if (++n >= maxaddrs)
+ goto done;
+ }
+ }
+ }
+
+ done:
+ *count = n;
+ _status = 0;
+
+ abort:
+ RFREE(AdapterAddresses);
+ return _status;
+}
+
+#endif //WIN32
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-win32.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-win32.h
new file mode 100644
index 0000000000..a00802192a
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs-win32.h
@@ -0,0 +1,13 @@
+/* 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/. */
+
+#ifndef STUN_IFADDRS_WIN32_H_
+#define STUN_IFADDRS_WIN32_H_
+
+#include "local_addr.h"
+
+int stun_getaddrs_filtered(nr_local_addr addrs[], int maxaddrs, int *count);
+
+#endif /* STUN_IFADDRS_WIN32_H_ */
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs.c
new file mode 100644
index 0000000000..362b7d828e
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs.c
@@ -0,0 +1,176 @@
+/*
+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.
+*/
+
+#include <csi_platform.h>
+#include <assert.h>
+#include <string.h>
+
+#ifdef WIN32
+#include "addrs-win32.h"
+#elif defined(BSD) || defined(DARWIN)
+#include "addrs-bsd.h"
+#else
+#include "addrs-netlink.h"
+#endif
+
+#include "stun.h"
+#include "addrs.h"
+#include "util.h"
+
+static int
+nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr)
+{
+ int i;
+ int different;
+
+ for (i = 0; i < count; ++i) {
+ different = nr_transport_addr_cmp(&addrs[i].addr, &(addr->addr),
+ NR_TRANSPORT_ADDR_CMP_MODE_ALL);
+ if (!different)
+ return 1; /* duplicate */
+ }
+
+ return 0;
+}
+
+int
+nr_stun_filter_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count)
+{
+ int r, _status;
+ nr_local_addr *tmp = 0;
+ int i;
+ int n;
+ /* We prefer temp ipv6 for their privacy properties. If we cannot get
+ * that, we prefer ipv6 that are not based on mac address. */
+ int filter_mac_ipv6 = 0;
+ int filter_teredo_ipv6 = 0;
+ int filter_non_temp_ipv6 = 0;
+
+ tmp = RMALLOC(*count * sizeof(*tmp));
+ if (!tmp)
+ ABORT(R_NO_MEMORY);
+
+ for (i = 0; i < *count; ++i) {
+ if (addrs[i].addr.ip_version == NR_IPV6) {
+ if (nr_transport_addr_is_teredo(&addrs[i].addr)) {
+ addrs[i].interface.type |= NR_INTERFACE_TYPE_TEREDO;
+ /* Prefer teredo over mac-based address. Probably will never see
+ * both. */
+ filter_mac_ipv6 = 1;
+ } else {
+ filter_teredo_ipv6 = 1;
+ }
+
+ if (!nr_transport_addr_is_mac_based(&addrs[i].addr)) {
+ filter_mac_ipv6 = 1;
+ }
+
+ if (addrs[i].flags & NR_ADDR_FLAG_TEMPORARY) {
+ filter_non_temp_ipv6 = 1;
+ }
+ }
+ }
+
+ 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].addr)) {
+ /* skip addrs[i], it's a loopback */
+ }
+ else if (remove_link_local &&
+ nr_transport_addr_is_link_local(&addrs[i].addr)) {
+ /* skip addrs[i], it's a link-local address */
+ }
+ else if (filter_mac_ipv6 &&
+ nr_transport_addr_is_mac_based(&addrs[i].addr)) {
+ /* skip addrs[i], it's MAC based */
+ }
+ else if (filter_teredo_ipv6 &&
+ nr_transport_addr_is_teredo(&addrs[i].addr)) {
+ /* skip addrs[i], it's a Teredo address */
+ }
+ else if (filter_non_temp_ipv6 &&
+ (addrs[i].addr.ip_version == NR_IPV6) &&
+ !(addrs[i].flags & NR_ADDR_FLAG_TEMPORARY)) {
+ /* skip addrs[i], it's a non-temporary ipv6, and we have a temporary */
+ }
+ else {
+ /* otherwise, copy it to the temporary array */
+ if ((r=nr_local_addr_copy(&tmp[n], &addrs[i])))
+ ABORT(r);
+ ++n;
+ }
+ }
+
+ *count = n;
+
+ memset(addrs, 0, *count * sizeof(*addrs));
+ /* copy temporary array into passed in/out array */
+ for (i = 0; i < *count; ++i) {
+ if ((r=nr_local_addr_copy(&addrs[i], &tmp[i])))
+ ABORT(r);
+ }
+
+ _status = 0;
+ abort:
+ RFREE(tmp);
+ return _status;
+}
+
+#ifndef USE_PLATFORM_NR_STUN_GET_ADDRS
+
+int
+nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
+{
+ int _status=0;
+ int i;
+ char typestr[100];
+
+ // Ensure output records are always fully defined. See bug 1589990.
+ if (maxaddrs > 0) {
+ memset(addrs, 0, maxaddrs * sizeof(nr_local_addr));
+ }
+
+ _status = stun_getaddrs_filtered(addrs, maxaddrs, count);
+
+ for (i = 0; i < *count; ++i) {
+ nr_local_addr_fmt_info_string(addrs+i,typestr,sizeof(typestr));
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n",
+ i,addrs[i].addr.as_string,addrs[i].addr.ifname,typestr);
+ }
+
+ return _status;
+}
+
+#endif
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs.h
new file mode 100644
index 0000000000..522bd92fd5
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/addrs.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 _addrs_h_
+#define _addrs_h_
+
+#include "transport_addr.h"
+#include "local_addr.h"
+
+int nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int *count);
+int nr_stun_filter_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count);
+
+#endif
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c
new file mode 100644
index 0000000000..4b5b92fb75
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c
@@ -0,0 +1,656 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+Copyright (c) 2013, Mozilla
+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.
+*/
+
+#include <nr_api.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <assert.h>
+#include <inttypes.h>
+
+#include "p_buf.h"
+#include "nr_socket.h"
+#include "stun.h"
+#include "nr_socket_buffered_stun.h"
+
+#define NR_MAX_FRAME_SIZE 0xFFFF
+
+typedef struct nr_frame_header_ {
+ UINT2 frame_length;
+ char data[0];
+} nr_frame_header;
+
+typedef struct nr_socket_buffered_stun_ {
+ nr_socket *inner;
+ nr_transport_addr remote_addr;
+ int connected;
+
+ /* Read state */
+ int read_state;
+#define NR_ICE_SOCKET_READ_NONE 0
+#define NR_ICE_SOCKET_READ_HDR 1
+#define NR_ICE_SOCKET_READ_FAILED 2
+ UCHAR *buffer;
+ size_t buffer_size;
+ size_t bytes_needed;
+ size_t bytes_read;
+ NR_async_cb readable_cb;
+ void *readable_cb_arg;
+
+ /* Write state */
+ nr_p_buf_ctx *p_bufs;
+ nr_p_buf_head pending_writes;
+ size_t pending;
+ size_t max_pending;
+ nr_framing_type framing_type;
+} nr_socket_buffered_stun;
+
+static int nr_socket_buffered_stun_destroy(void **objp);
+static int nr_socket_buffered_stun_sendto(void *obj,const void *msg, size_t len,
+ int flags, const nr_transport_addr *to);
+static int nr_socket_buffered_stun_recvfrom(void *obj,void * restrict buf,
+ size_t maxlen, size_t *len, int flags, nr_transport_addr *from);
+static int nr_socket_buffered_stun_getfd(void *obj, NR_SOCKET *fd);
+static int nr_socket_buffered_stun_getaddr(void *obj, nr_transport_addr *addrp);
+static int nr_socket_buffered_stun_close(void *obj);
+static int nr_socket_buffered_stun_connect(void *sock, const nr_transport_addr *addr);
+static int nr_socket_buffered_stun_write(void *obj,const void *msg, size_t len, size_t *written);
+static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg);
+static int nr_socket_buffered_stun_listen(void *obj, int backlog);
+static int nr_socket_buffered_stun_accept(void *obj, nr_transport_addr *addrp, nr_socket **sockp);
+
+static nr_socket_vtbl nr_socket_buffered_stun_vtbl={
+ 2,
+ nr_socket_buffered_stun_destroy,
+ nr_socket_buffered_stun_sendto,
+ nr_socket_buffered_stun_recvfrom,
+ nr_socket_buffered_stun_getfd,
+ nr_socket_buffered_stun_getaddr,
+ nr_socket_buffered_stun_connect,
+ 0,
+ 0,
+ nr_socket_buffered_stun_close,
+ nr_socket_buffered_stun_listen,
+ nr_socket_buffered_stun_accept
+};
+
+void nr_socket_buffered_stun_set_readable_cb(nr_socket *sock,
+ NR_async_cb readable_cb, void *readable_cb_arg)
+{
+ nr_socket_buffered_stun *buf_sock = (nr_socket_buffered_stun *)sock->obj;
+
+ buf_sock->readable_cb = readable_cb;
+ buf_sock->readable_cb_arg = readable_cb_arg;
+}
+
+int nr_socket_buffered_set_connected_to(nr_socket *sock, nr_transport_addr *remote_addr)
+{
+ nr_socket_buffered_stun *buf_sock = (nr_socket_buffered_stun *)sock->obj;
+ int r, _status;
+
+ if ((r=nr_transport_addr_copy(&buf_sock->remote_addr, remote_addr)))
+ ABORT(r);
+
+ buf_sock->connected = 1;
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+int nr_socket_buffered_stun_create(nr_socket *inner, int max_pending,
+ nr_framing_type framing_type, nr_socket **sockp)
+{
+ int r, _status;
+ nr_socket_buffered_stun *sock = 0;
+ size_t frame_size;
+
+ if (!(sock = RCALLOC(sizeof(nr_socket_buffered_stun))))
+ ABORT(R_NO_MEMORY);
+
+ sock->inner = inner;
+ sock->framing_type = framing_type;
+
+ if ((r=nr_ip4_port_to_transport_addr(INADDR_ANY, 0, IPPROTO_TCP, &sock->remote_addr)))
+ ABORT(r);
+
+ switch (framing_type) {
+ case ICE_TCP_FRAMING:
+ frame_size = sizeof(nr_frame_header);
+ sock->buffer_size = sizeof(nr_frame_header) + NR_MAX_FRAME_SIZE;
+ sock->bytes_needed = sizeof(nr_frame_header);
+ break;
+ case TURN_TCP_FRAMING:
+ frame_size = 0;
+ sock->buffer_size = NR_STUN_MAX_MESSAGE_SIZE;
+ sock->bytes_needed = sizeof(nr_stun_message_header);
+ break;
+ default:
+ assert(0);
+ ABORT(R_BAD_ARGS);
+ }
+
+ /* TODO(ekr@rtfm.com): Check this */
+ if (!(sock->buffer = RMALLOC(sock->buffer_size)))
+ ABORT(R_NO_MEMORY);
+
+ sock->read_state = NR_ICE_SOCKET_READ_NONE;
+ sock->connected = 0;
+
+ STAILQ_INIT(&sock->pending_writes);
+ if ((r=nr_p_buf_ctx_create(sock->buffer_size, &sock->p_bufs)))
+ ABORT(r);
+ sock->max_pending = max_pending + frame_size;
+
+ if ((r=nr_socket_create_int(sock, &nr_socket_buffered_stun_vtbl, sockp)))
+ ABORT(r);
+
+ _status=0;
+abort:
+ if (_status && sock) {
+ void *sock_v = sock;
+ sock->inner = 0; /* Give up ownership so we don't destroy */
+ nr_socket_buffered_stun_destroy(&sock_v);
+ }
+ return(_status);
+}
+
+/* Note: This destroys the inner socket */
+int nr_socket_buffered_stun_destroy(void **objp)
+{
+ nr_socket_buffered_stun *sock;
+ NR_SOCKET fd;
+
+ if (!objp || !*objp)
+ return 0;
+
+ sock = (nr_socket_buffered_stun *)*objp;
+ *objp = 0;
+
+ /* Free the buffer if needed */
+ RFREE(sock->buffer);
+
+ /* Cancel waiting on the socket */
+ if (sock->inner && !nr_socket_getfd(sock->inner, &fd)) {
+ NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_WRITE);
+ NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
+ }
+
+ nr_p_buf_free_chain(sock->p_bufs, &sock->pending_writes);
+ nr_p_buf_ctx_destroy(&sock->p_bufs);
+ nr_socket_destroy(&sock->inner);
+ RFREE(sock);
+
+ return 0;
+}
+
+static int nr_socket_buffered_stun_sendto(void *obj,const void *msg, size_t len,
+ int flags, const nr_transport_addr *to)
+{
+ nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj;
+ int r, _status;
+ size_t written;
+ nr_frame_header *frame = NULL;
+
+ /* Check that we are writing to the connected address if
+ connected */
+ if (!nr_transport_addr_is_wildcard(&sock->remote_addr)) {
+ if (nr_transport_addr_cmp(&sock->remote_addr, to, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
+ r_log(LOG_GENERIC, LOG_ERR, "Sendto on connected socket doesn't match");
+ ABORT(R_BAD_DATA);
+ }
+ }
+
+ if (sock->framing_type == ICE_TCP_FRAMING) {
+
+ assert(len <= NR_MAX_FRAME_SIZE);
+ if (len > NR_MAX_FRAME_SIZE)
+ ABORT(R_FAILED);
+
+ if (!(frame = RMALLOC(len + sizeof(nr_frame_header))))
+ ABORT(R_NO_MEMORY);
+
+ frame->frame_length = htons(len);
+ memcpy(frame->data, msg, len);
+ len += sizeof(nr_frame_header);
+ msg = frame;
+ }
+
+ if ((r=nr_socket_buffered_stun_write(obj, msg, len, &written)))
+ ABORT(r);
+
+ if (len != written)
+ ABORT(R_IO_ERROR);
+
+ _status=0;
+abort:
+ RFREE(frame);
+ return _status;
+}
+
+static void nr_socket_buffered_stun_failed(nr_socket_buffered_stun *sock)
+ {
+ NR_SOCKET fd;
+
+ sock->read_state = NR_ICE_SOCKET_READ_FAILED;
+
+ /* Cancel waiting on the socket */
+ if (sock->inner && !nr_socket_getfd(sock->inner, &fd)) {
+ NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_WRITE);
+ NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
+ }
+ }
+
+static int nr_socket_buffered_stun_recvfrom(void *obj,void * restrict buf,
+ size_t maxlen, size_t *len, int flags, nr_transport_addr *from)
+{
+ int r, _status;
+ size_t bytes_read;
+ nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj;
+ nr_frame_header *frame = (nr_frame_header *)sock->buffer;
+ size_t skip_hdr_size = (sock->framing_type == ICE_TCP_FRAMING) ? sizeof(nr_frame_header) : 0;
+
+ if (sock->read_state == NR_ICE_SOCKET_READ_FAILED) {
+ ABORT(R_FAILED);
+ }
+
+ while (sock->bytes_needed) {
+ /* Read all the expected bytes */
+ assert(sock->bytes_needed <= sock->buffer_size - sock->bytes_read);
+
+ if(r=nr_socket_read(sock->inner,
+ sock->buffer + sock->bytes_read,
+ sock->bytes_needed, &bytes_read, 0))
+ ABORT(r);
+
+ assert(bytes_read <= sock->bytes_needed);
+ sock->bytes_needed -= bytes_read;
+ sock->bytes_read += bytes_read;
+
+ /* Unfinished */
+ if (sock->bytes_needed)
+ ABORT(R_WOULDBLOCK);
+
+ /* No more bytes expected */
+ if (sock->read_state == NR_ICE_SOCKET_READ_NONE) {
+ size_t remaining_length;
+ if (sock->framing_type == ICE_TCP_FRAMING) {
+ if (sock->bytes_read < sizeof(nr_frame_header))
+ ABORT(R_BAD_DATA);
+ remaining_length = ntohs(frame->frame_length);
+ } else {
+ int tmp_length;
+
+ /* Parse the header */
+ if (r = nr_stun_message_length(sock->buffer, sock->bytes_read, &tmp_length))
+ ABORT(r);
+ assert(tmp_length >= 0);
+ if (tmp_length < 0)
+ ABORT(R_BAD_DATA);
+ remaining_length = tmp_length;
+
+ }
+ /* Check to see if we have enough room */
+ if ((sock->buffer_size - sock->bytes_read) < remaining_length)
+ ABORT(R_BAD_DATA);
+
+ sock->read_state = NR_ICE_SOCKET_READ_HDR;
+ /* Set ourselves up to read the rest of the data */
+ sock->bytes_needed = remaining_length;
+ }
+ }
+
+ assert(skip_hdr_size <= sock->bytes_read);
+ if (skip_hdr_size > sock->bytes_read)
+ ABORT(R_BAD_DATA);
+ sock->bytes_read -= skip_hdr_size;
+
+ if (maxlen < sock->bytes_read)
+ ABORT(R_BAD_ARGS);
+
+ *len = sock->bytes_read;
+ memcpy(buf, sock->buffer + skip_hdr_size, sock->bytes_read);
+
+ sock->bytes_read = 0;
+ sock->read_state = NR_ICE_SOCKET_READ_NONE;
+ sock->bytes_needed = (sock->framing_type == ICE_TCP_FRAMING) ? sizeof(nr_frame_header) : sizeof(nr_stun_message_header);
+
+ if ((r = nr_transport_addr_copy(from, &sock->remote_addr))) ABORT(r);
+
+ _status=0;
+abort:
+ if (_status && (_status != R_WOULDBLOCK)) {
+ nr_socket_buffered_stun_failed(sock);
+ }
+
+ return(_status);
+}
+
+static int nr_socket_buffered_stun_getfd(void *obj, NR_SOCKET *fd)
+{
+ nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj;
+
+ return nr_socket_getfd(sock->inner, fd);
+}
+
+static int nr_socket_buffered_stun_getaddr(void *obj, nr_transport_addr *addrp)
+{
+ nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj;
+
+ return nr_socket_getaddr(sock->inner, addrp);
+}
+
+static int nr_socket_buffered_stun_close(void *obj)
+{
+ nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj;
+ NR_SOCKET fd;
+
+ /* Cancel waiting on the socket */
+ if (sock->inner && !nr_socket_getfd(sock->inner, &fd)) {
+ NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_WRITE);
+ }
+
+ return nr_socket_close(sock->inner);
+}
+
+static int nr_socket_buffered_stun_listen(void *obj, int backlog)
+{
+ int r, _status;
+ nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj;
+
+ if (!sock->inner)
+ ABORT(R_FAILED);
+
+ if ((r=nr_socket_listen(sock->inner, backlog)))
+ ABORT(r);
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+
+static int nr_socket_buffered_stun_accept(void *obj, nr_transport_addr *addrp, nr_socket **sockp)
+{
+ nr_socket_buffered_stun *bsock = (nr_socket_buffered_stun *)obj;
+
+ return nr_socket_accept(bsock->inner, addrp, sockp);
+}
+
+static void nr_socket_buffered_stun_connected_cb(NR_SOCKET s, int how, void *arg)
+{
+ nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)arg;
+ int r, _status;
+ NR_SOCKET fd;
+
+ assert(!sock->connected);
+
+ sock->connected = 1;
+
+ if ((r=nr_socket_getfd(sock->inner, &fd)))
+ ABORT(r);
+ NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_WRITE);
+
+ // once connected arm for read
+ if (sock->readable_cb) {
+ NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, sock->readable_cb, sock->readable_cb_arg);
+ }
+
+ if (sock->pending) {
+ r_log(LOG_GENERIC, LOG_INFO, "Invoking writable_cb on connected (%u)", (uint32_t) sock->pending);
+ nr_socket_buffered_stun_writable_cb(s, how, arg);
+ }
+
+ _status=0;
+abort:
+ if (_status) {
+ r_log(LOG_GENERIC, LOG_ERR, "Failure in nr_socket_buffered_stun_connected_cb: %d", _status);
+
+ }
+}
+
+static int nr_socket_buffered_stun_connect(void *obj, const nr_transport_addr *addr)
+{
+ nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj;
+ int r, _status;
+
+ if ((r=nr_transport_addr_copy(&sock->remote_addr, addr)))
+ ABORT(r);
+
+ if ((r=nr_socket_connect(sock->inner, addr))) {
+ if (r == R_WOULDBLOCK) {
+ NR_SOCKET fd;
+
+ if ((r=nr_socket_getfd(sock->inner, &fd)))
+ ABORT(r);
+
+ NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_WRITE, nr_socket_buffered_stun_connected_cb, sock);
+ ABORT(R_WOULDBLOCK);
+ }
+ ABORT(r);
+ } else {
+ r_log(LOG_GENERIC, LOG_INFO, "Connected without blocking");
+ sock->connected = 1;
+ }
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+static int nr_socket_buffered_stun_arm_writable_cb(nr_socket_buffered_stun *sock)
+{
+ int r, _status;
+ NR_SOCKET fd;
+
+ if ((r=nr_socket_getfd(sock->inner, &fd)))
+ ABORT(r);
+
+ NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_WRITE, nr_socket_buffered_stun_writable_cb, sock);
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+static int nr_socket_buffered_stun_write(void *obj,const void *msg, size_t len, size_t *written)
+{
+ nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj;
+ int already_armed = 0;
+ int r,_status;
+ size_t written2 = 0;
+ size_t original_len = len;
+
+ /* Buffers are close to full, report error. Do this now so we never
+ get partial writes */
+ if ((sock->pending + len) > sock->max_pending) {
+ r_log(LOG_GENERIC, LOG_INFO, "Write buffer for %s full (%u + %u > %u) - re-arming @%p",
+ sock->remote_addr.as_string, (uint32_t)sock->pending, (uint32_t)len, (uint32_t)sock->max_pending,
+ &(sock->pending));
+ ABORT(R_WOULDBLOCK);
+ }
+
+
+ if (sock->connected && !sock->pending) {
+ r = nr_socket_write(sock->inner, msg, len, &written2, 0);
+ if (r) {
+ if (r != R_WOULDBLOCK) {
+ r_log(LOG_GENERIC, LOG_ERR, "Write error for %s - %d",
+ sock->remote_addr.as_string, r);
+ ABORT(r);
+ }
+ r_log(LOG_GENERIC, LOG_INFO, "Write of %" PRIu64 " blocked for %s",
+ (uint64_t) len, sock->remote_addr.as_string);
+
+ written2=0;
+ }
+ } else {
+ already_armed = 1;
+ }
+
+ /* Buffer what's left */
+ len -= written2;
+
+ if (len) {
+ if ((r=nr_p_buf_write_to_chain(sock->p_bufs, &sock->pending_writes,
+ ((UCHAR *)msg) + written2, len))) {
+ r_log(LOG_GENERIC, LOG_ERR, "Write_to_chain error for %s - %d",
+ sock->remote_addr.as_string, r);
+
+ ABORT(r);
+ }
+
+ sock->pending += len;
+ }
+
+ if (sock->pending) {
+ if (!already_armed) {
+ if ((r=nr_socket_buffered_stun_arm_writable_cb(sock)))
+ ABORT(r);
+ }
+ r_log(LOG_GENERIC, LOG_INFO, "Write buffer not empty for %s %u - %s armed (@%p),%s connected",
+ sock->remote_addr.as_string, (uint32_t)sock->pending,
+ already_armed ? "already" : "", &sock->pending,
+ sock->connected ? "" : " not");
+ }
+
+ *written = original_len;
+
+ _status=0;
+abort:
+ return _status;
+}
+
+static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg)
+{
+ nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)arg;
+ int r,_status;
+ nr_p_buf *n1, *n2;
+
+ if (sock->read_state == NR_ICE_SOCKET_READ_FAILED) {
+ ABORT(R_FAILED);
+ }
+
+ /* Try to flush */
+ STAILQ_FOREACH_SAFE(n1, &sock->pending_writes, entry, n2) {
+ size_t written = 0;
+
+ if ((r=nr_socket_write(sock->inner, n1->data + n1->r_offset,
+ n1->length - n1->r_offset,
+ &written, 0))) {
+
+ r_log(LOG_GENERIC, LOG_ERR, "Write error for %s - %d",
+ sock->remote_addr.as_string, r);
+ ABORT(r);
+ }
+
+ n1->r_offset += written;
+ assert(sock->pending >= written);
+ sock->pending -= written;
+
+ if (n1->r_offset < n1->length) {
+ /* We wrote something, but not everything */
+ r_log(LOG_GENERIC, LOG_INFO, "Write in callback didn't write all (remaining %u of %u) for %s",
+ n1->length - n1->r_offset, n1->length,
+ sock->remote_addr.as_string);
+ ABORT(R_WOULDBLOCK);
+ }
+
+ /* We are done with this p_buf */
+ STAILQ_REMOVE_HEAD(&sock->pending_writes, entry);
+ nr_p_buf_free(sock->p_bufs, n1);
+ }
+
+ assert(!sock->pending);
+ _status=0;
+abort:
+ r_log(LOG_GENERIC, LOG_INFO, "Writable_cb %s (%u (%p) pending)",
+ sock->remote_addr.as_string, (uint32_t)sock->pending, &(sock->pending));
+ if (_status && _status != R_WOULDBLOCK) {
+ r_log(LOG_GENERIC, LOG_ERR, "Failure in writable_cb: %d", _status);
+ nr_socket_buffered_stun_failed(sock);
+ /* Report this failure up; the only way to do this is a readable callback.
+ * Once the user tries to read (using nr_socket_buffered_stun_recvfrom), it
+ * will notice that there has been a failure. */
+ if (sock->readable_cb) {
+ sock->readable_cb(s, NR_ASYNC_WAIT_READ, sock->readable_cb_arg);
+ }
+ } else if (sock->pending) {
+ nr_socket_buffered_stun_arm_writable_cb(sock);
+ }
+}
+
+int nr_socket_buffered_stun_reset(nr_socket* sock_arg, nr_socket* new_inner) {
+ int r, _status;
+ NR_SOCKET fd;
+
+ nr_socket_buffered_stun* sock = (nr_socket_buffered_stun*)sock_arg->obj;
+
+ if (sock->inner && !nr_socket_getfd(sock->inner, &fd)) {
+ r_log(LOG_GENERIC, LOG_DEBUG, "In %s, canceling wait on old socket", __FUNCTION__);
+ NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_WRITE);
+ NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
+ }
+
+ nr_socket_destroy(&sock->inner);
+ sock->inner = new_inner;
+
+ sock->read_state = NR_ICE_SOCKET_READ_NONE;
+ sock->connected = 0;
+
+ sock->bytes_read = 0;
+ sock->bytes_needed = (sock->framing_type == ICE_TCP_FRAMING)
+ ? sizeof(nr_frame_header)
+ : sizeof(nr_stun_message_header);
+ sock->pending = 0;
+
+ nr_p_buf_free_chain(sock->p_bufs, &sock->pending_writes);
+ nr_p_buf_ctx_destroy(&sock->p_bufs);
+
+ STAILQ_INIT(&sock->pending_writes);
+
+ if ((r = nr_p_buf_ctx_create(sock->buffer_size, &sock->p_bufs))) {
+ ABORT(r);
+ }
+
+ if ((r = nr_ip4_port_to_transport_addr(INADDR_ANY, 0, IPPROTO_TCP,
+ &sock->remote_addr))) {
+ ABORT(r);
+ }
+
+ _status = 0;
+abort:
+ return (_status);
+}
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_buffered_stun.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_buffered_stun.h
new file mode 100644
index 0000000000..c635ee393d
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_buffered_stun.h
@@ -0,0 +1,66 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+Copyright (c) 2013, Mozilla
+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_buffered_stun_h
+#define _nr_socket_buffered_stun_h
+
+#include "nr_socket.h"
+
+/* Wrapper socket which provides buffered STUN-oriented I/O
+
+ 1. Writes don't block and are automatically flushed when needed.
+ 2. All reads are in units of STUN messages
+
+ This socket takes ownership of the inner socket |sock|.
+ */
+
+typedef enum {
+ TURN_TCP_FRAMING=0,
+ ICE_TCP_FRAMING
+} nr_framing_type;
+
+void nr_socket_buffered_stun_set_readable_cb(nr_socket *sock,
+ NR_async_cb readable_cb, void *readable_cb_arg);
+
+int nr_socket_buffered_stun_create(nr_socket *inner, int max_pending,
+ nr_framing_type framing_type, nr_socket **sockp);
+
+int nr_socket_buffered_set_connected_to(nr_socket *sock,
+ nr_transport_addr *remote_addr);
+
+int nr_socket_buffered_stun_reset(nr_socket *sock, nr_socket *new_inner);
+
+#endif
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_turn.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_turn.c
new file mode 100644
index 0000000000..1a0162b13e
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_turn.c
@@ -0,0 +1,195 @@
+/*
+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.
+*/
+
+#ifdef USE_TURN
+
+#include <csi_platform.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include "stun.h"
+#include "turn_client_ctx.h"
+#include "nr_socket_turn.h"
+
+
+static char *nr_socket_turn_magic_cookie = "nr_socket_turn";
+
+typedef struct nr_socket_turn_ {
+ char *magic_cookie;
+ nr_turn_client_ctx *turn;
+} 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, const 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={
+ 2,
+ nr_socket_turn_destroy,
+ nr_socket_turn_sendto,
+ nr_socket_turn_recvfrom,
+ nr_socket_turn_getfd,
+ nr_socket_turn_getaddr,
+ 0,
+ 0,
+ 0,
+ nr_socket_turn_close,
+ 0,
+ 0
+};
+
+int nr_socket_turn_create(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;
+
+ 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);
+ }
+
+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;
+ return(_status);
+ }
+
+static int nr_socket_turn_sendto(void *obj,const void *msg, size_t len,
+ int flags, const nr_transport_addr *addr)
+ {
+ int r,_status;
+ nr_socket_turn *sturn=obj;
+
+ assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+ assert(sturn->turn);
+
+ if ((r = nr_turn_client_send_indication(sturn->turn, msg, len, flags,
+ addr)))
+ ABORT(r);
+
+ _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)
+ {
+ /* Reading from TURN sockets is done by the indication
+ processing code in turn_client_ctx. */
+ assert(0);
+
+ return(R_INTERNAL);
+ }
+
+static int nr_socket_turn_getfd(void *obj, NR_SOCKET *fd)
+ {
+ /* You should never directly be touching this fd. */
+ assert(0);
+
+ return(R_INTERNAL);
+ }
+
+static int nr_socket_turn_getaddr(void *obj, nr_transport_addr *addrp)
+ {
+ nr_socket_turn *sturn=obj;
+ int r, _status;
+
+ assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+ assert(sturn->turn);
+
+ /* This returns the relayed address */
+ if ((r=nr_turn_client_get_relayed_address(sturn->turn, addrp)))
+ ABORT(r);
+
+ _status=0;
+ abort:
+ return(_status);
+ }
+
+static int nr_socket_turn_close(void *obj)
+ {
+ /* No-op */
+#ifndef NDEBUG
+ nr_socket_turn *sturn=obj;
+ assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+#endif
+
+ return 0;
+ }
+
+int nr_socket_turn_set_ctx(nr_socket *sock, nr_turn_client_ctx *ctx)
+{
+ nr_socket_turn *sturn=(nr_socket_turn*)sock->obj;
+ assert(sturn->magic_cookie == nr_socket_turn_magic_cookie);
+ assert(!sturn->turn);
+
+ sturn->turn = ctx;
+
+ return 0;
+}
+
+#endif /* USE_TURN */
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_turn.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_turn.h
new file mode 100644
index 0000000000..13506045a8
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/nr_socket_turn.h
@@ -0,0 +1,48 @@
+/*
+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
+
+#include "nr_socket.h"
+
+/* This is a partial implementation of an nr_socket wrapped
+ around TURN. It implements only the nr_socket features
+ actually used by the ICE stack. You can't, for instance,
+ read off the socket */
+int nr_socket_turn_create(nr_socket **sockp);
+int nr_socket_turn_set_ctx(nr_socket *sock, nr_turn_client_ctx *ctx);
+
+#endif
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun.h
new file mode 100644
index 0000000000..a32751d795
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun.h
@@ -0,0 +1,218 @@
+/*
+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>
+#ifndef LINUX
+#include <net/if.h>
+#ifdef DARWIN
+#include <net/if_var.h>
+#endif
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#else
+#include <linux/if.h>
+#endif
+#ifndef BSD
+#include <net/route.h>
+#endif
+#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
+/* from an expired draft defined as optional, but in the required range */
+#define NR_STUN_ATTR_BANDWIDTH 0x0010
+#define NR_STUN_ATTR_XOR_PEER_ADDRESS 0x0012
+#define NR_STUN_ATTR_DATA 0x0013
+#define NR_STUN_ATTR_XOR_RELAY_ADDRESS 0x0016
+#define NR_STUN_ATTR_REQUESTED_TRANSPORT 0x0019
+
+#define NR_STUN_ATTR_REQUESTED_TRANSPORT_UDP 17
+#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_REFRESH 0x004
+
+#define NR_METHOD_SEND 0x006
+#define NR_METHOD_DATA 0x007
+#define NR_METHOD_CREATE_PERMISSION 0x008
+#define NR_METHOD_CHANNEL_BIND 0x009
+
+/* 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_REFRESH_REQUEST NR_STUN_TYPE(NR_METHOD_REFRESH, \
+ NR_CLASS_REQUEST)
+#define NR_STUN_MSG_REFRESH_RESPONSE NR_STUN_TYPE(NR_METHOD_REFRESH, \
+ NR_CLASS_RESPONSE)
+#define NR_STUN_MSG_REFRESH_ERROR_RESPONSE NR_STUN_TYPE(NR_METHOD_REFRESH, \
+ 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)
+
+#define NR_STUN_MSG_PERMISSION_REQUEST NR_STUN_TYPE(NR_METHOD_CREATE_PERMISSION, \
+ NR_CLASS_REQUEST)
+#define NR_STUN_MSG_PERMISSION_RESPONSE NR_STUN_TYPE(NR_METHOD_CREATE_PERMISSION, \
+ NR_CLASS_RESPONSE)
+#define NR_STUN_MSG_PERMISSION_ERROR_RESPONSE NR_STUN_TYPE(NR_METHOD_CREATE_PERMISSION, \
+ NR_CLASS_ERROR_RESPONSE)
+
+#define NR_STUN_MSG_CHANNEL_BIND_REQUEST NR_STUN_TYPE(NR_METHOD_CHANNEL_BIND, \
+ NR_CLASS_REQUEST)
+#define NR_STUN_MSG_CHANNEL_BIND_RESPONSE NR_STUN_TYPE(NR_METHOD_CHANNEL_BIND, \
+ NR_CLASS_RESPONSE)
+#define NR_STUN_MSG_CHANNEL_BIND_ERROR_RESPONSE NR_STUN_TYPE(NR_METHOD_CHANNEL_BIND, \
+ NR_CLASS_ERROR_RESPONSE)
+
+
+#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
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_build.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_build.c
new file mode 100644
index 0000000000..001b38e7c4
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_build.c
@@ -0,0 +1,611 @@
+/*
+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.
+*/
+
+#include <csi_platform.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.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:
+ if ((r=nr_stun_message_add_fingerprint_attribute(req)))
+ ABORT(r);
+ /* fall through */
+ case NR_STUN_MODE_STUN_NO_AUTH:
+ req->header.magic_cookie = NR_STUN_MAGIC_COOKIE;
+ 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_NO_AUTH, 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_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_use_candidate_attribute(req)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_add_priority_attribute(req, params->priority)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_add_ice_controlling_attribute(req, params->tiebreaker)))
+ 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;
+ default:
+ assert(0);
+ ABORT(R_INTERNAL);
+ }
+
+ *msg = req;
+
+ _status=0;
+ abort:
+ if (_status) nr_stun_message_destroy(&req);
+ return _status;
+}
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+
+#ifndef __isascii
+#define __isascii(c) (((c) & ~0x7F) == 0)
+#endif
+
+/* Long-term passwords are computed over the key:
+
+ key = MD5(username ":" realm ":" SASLprep(password))
+
+ Per RFC 5389 S 15.4
+*/
+int
+nr_stun_compute_lt_message_integrity_password(const char *username, const char *realm,
+ Data *password, Data *hmac_key)
+{
+ char digest_input[1000];
+ size_t i;
+ int r, _status;
+ size_t len;
+
+ /* First check that the password is ASCII. We are supposed to
+ SASLprep but we don't support this yet
+ TODO(ekr@rtfm.com): Add SASLprep for password.
+ */
+ for (i=0; i<password->len; i++) {
+ if (!__isascii(password->data[i]))
+ ABORT(R_BAD_DATA);
+ }
+
+ if (hmac_key->len < 16)
+ ABORT(R_BAD_ARGS);
+
+ snprintf(digest_input, sizeof(digest_input), "%s:%s:", username, realm);
+ if ((sizeof(digest_input) - strlen(digest_input)) < password->len)
+ ABORT(R_BAD_DATA);
+
+ len = strlen(digest_input);
+ memcpy(digest_input + len, password->data, password->len);
+
+
+ if (r=nr_crypto_md5((UCHAR *)digest_input, len + password->len, hmac_key->data))
+ ABORT(r);
+ hmac_key->len=16;
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+static int
+nr_stun_build_auth_params(nr_stun_client_auth_params *auth, nr_stun_message *req)
+{
+ int r, _status;
+ UCHAR hmac_key_d[16];
+ Data hmac_key;
+
+ ATTACH_DATA(hmac_key, hmac_key_d);
+
+ if (!auth->authenticate)
+ goto done;
+
+ assert(auth->username);
+ assert(auth->password.len);
+ assert(auth->realm);
+ assert(auth->nonce);
+
+ if (r=nr_stun_compute_lt_message_integrity_password(auth->username,
+ auth->realm,
+ &auth->password,
+ &hmac_key))
+ ABORT(r);
+
+ if (!auth->username) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no username provided");
+ ABORT(R_INTERNAL);
+ }
+
+ if (!auth->password.len) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no password provided");
+ ABORT(R_INTERNAL);
+ }
+
+ if (!auth->realm) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no realm provided");
+ ABORT(R_INTERNAL);
+ }
+
+ if (!auth->nonce) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no nonce provided");
+ ABORT(R_INTERNAL);
+ }
+
+ if ((r=nr_stun_message_add_username_attribute(req, auth->username)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_add_realm_attribute(req, auth->realm)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_add_nonce_attribute(req, auth->nonce)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_add_message_integrity_attribute(req, &hmac_key)))
+ ABORT(r);
+
+done:
+ _status=0;
+abort:
+ return(_status);
+}
+
+int
+nr_stun_build_allocate_request(nr_stun_client_auth_params *auth, nr_stun_client_allocate_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_ALLOCATE_REQUEST, &req)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_add_requested_transport_attribute(req, NR_STUN_ATTR_REQUESTED_TRANSPORT_UDP)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs)))
+ ABORT(r);
+
+ /* TODO(ekr@rtfm.com): Add the SOFTWARE attribute (Firefox bug 857666) */
+
+ if ((r=nr_stun_build_auth_params(auth, req)))
+ ABORT(r);
+
+ *msg = req;
+
+ _status=0;
+ abort:
+ if (_status) nr_stun_message_destroy(&req);
+ return _status;
+}
+
+
+int nr_stun_build_refresh_request(nr_stun_client_auth_params *auth, nr_stun_client_refresh_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_REFRESH_REQUEST, &req)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs)))
+ ABORT(r);
+
+
+ /* TODO(ekr@rtfm.com): Add the SOFTWARE attribute (Firefox bug 857666) */
+
+ if ((r=nr_stun_build_auth_params(auth, req)))
+ ABORT(r);
+
+ *msg = req;
+
+ _status=0;
+ abort:
+ if (_status) nr_stun_message_destroy(&req);
+ return _status;
+}
+
+
+int nr_stun_build_permission_request(nr_stun_client_auth_params *auth, nr_stun_client_permission_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_PERMISSION_REQUEST, &req)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_add_xor_peer_address_attribute(req, &params->remote_addr)))
+ ABORT(r);
+
+ if ((r=nr_stun_build_auth_params(auth, req)))
+ 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_xor_peer_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_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_xor_peer_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_INFO, "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) */
+
+ 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) {
+ 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);
+ }
+}
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_build.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_build.h
new file mode 100644
index 0000000000..c3f91a87b0
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_build.h
@@ -0,0 +1,147 @@
+/*
+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 */
+#define NR_STUN_MODE_STUN_NO_AUTH 3
+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_ {
+#if defined(WIN32) || defined(__clang__)
+ // VC++ and clang give error and warning respectively 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_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_use_candidate(nr_stun_client_ice_binding_request_params *params, nr_stun_message **msg);
+
+int nr_stun_build_req_ice(nr_stun_client_ice_binding_request_params *params, nr_stun_message **msg);
+#endif /* USE_ICE */
+
+
+typedef struct nr_stun_client_auth_params_ {
+ char authenticate;
+ char *username;
+ char *realm;
+ char *nonce;
+ Data password;
+} nr_stun_client_auth_params;
+
+#ifdef USE_TURN
+typedef struct nr_stun_client_allocate_request_params_ {
+ UINT4 lifetime_secs;
+} nr_stun_client_allocate_request_params;
+
+int nr_stun_build_allocate_request(nr_stun_client_auth_params *auth, nr_stun_client_allocate_request_params *params, nr_stun_message **msg);
+
+
+typedef struct nr_stun_client_refresh_request_params_ {
+ UINT4 lifetime_secs;
+} nr_stun_client_refresh_request_params;
+
+int nr_stun_build_refresh_request(nr_stun_client_auth_params *auth, nr_stun_client_refresh_request_params *params, nr_stun_message **msg);
+
+
+
+typedef struct nr_stun_client_permission_request_params_ {
+ nr_transport_addr remote_addr;
+} nr_stun_client_permission_request_params;
+
+int nr_stun_build_permission_request(nr_stun_client_auth_params *auth, nr_stun_client_permission_request_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_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);
+int nr_stun_compute_lt_message_integrity_password(const char *username, const char *realm,
+ Data *password, Data *hmac_key);
+
+#endif
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_client_ctx.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_client_ctx.c
new file mode 100644
index 0000000000..50b9f74a5b
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_client_ctx.c
@@ -0,0 +1,888 @@
+/*
+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.
+*/
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+
+#include <nr_api.h>
+#include "stun.h"
+#include "async_timer.h"
+#include "registry.h"
+#include "stun_reg.h"
+#include "nr_crypto.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);
+
+#define NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD 1
+#define NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK 2
+
+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;
+ char allow_loopback;
+ 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);
+ assert(ctx->my_addr.protocol==ctx->peer_addr.protocol);
+
+ if (RTO != 0) {
+ ctx->rto_ms = RTO;
+ } else if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_RETRANSMIT_TIMEOUT, &ctx->rto_ms)) {
+ 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->maximum_transmits_timeout_ms))
+ ctx->maximum_transmits_timeout_ms = 16 * ctx->rto_ms;
+
+ ctx->mapped_addr_check_mask = NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD;
+ if (NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, &allow_loopback) ||
+ !allow_loopback) {
+ ctx->mapped_addr_check_mask |= NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK;
+ }
+
+ if (ctx->my_addr.protocol == IPPROTO_TCP) {
+ /* Because TCP is reliable there is only one final timeout value.
+ * We store the timeout value for TCP in here, because timeout_ms gets
+ * reset to 0 in client_reset() which gets called from client_start() */
+ ctx->maximum_transmits_timeout_ms = ctx->rto_ms *
+ pow(ctx->retransmission_backoff_factor,
+ ctx->maximum_transmits);
+ ctx->maximum_transmits = 1;
+ }
+
+ *ctxp=ctx;
+
+ _status=0;
+ abort:
+ if(_status){
+ nr_stun_client_ctx_destroy(&ctx);
+ }
+ return(_status);
+ }
+
+static void nr_stun_client_fire_finished_cb(nr_stun_client_ctx *ctx)
+ {
+ 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);
+ }
+ }
+
+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) {
+ nr_stun_client_fire_finished_cb(ctx);
+ }
+
+ return(_status);
+ }
+
+ int nr_stun_client_restart(nr_stun_client_ctx* ctx,
+ const nr_transport_addr* peer_addr) {
+ int r,_status;
+ int mode;
+ NR_async_cb finished_cb;
+ void *cb_arg;
+ if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
+ ABORT(R_NOT_PERMITTED);
+
+ mode = ctx->mode;
+ finished_cb = ctx->finished_cb;
+ cb_arg = ctx->cb_arg;
+
+ nr_stun_client_reset(ctx);
+ nr_transport_addr_copy(&ctx->peer_addr, peer_addr);
+
+ 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_INFO,"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);
+
+ // track retransmits for ice telemetry
+ nr_accumulate_count(&(ctx->retransmit_ct), 1);
+
+ /* 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;
+ }
+
+ nr_stun_client_fire_finished_cb(ctx);
+ }
+ if (_status) {
+ // cb doesn't return anything, but we should probably log that we aborted
+ // This also quiets the unused variable warnings.
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired cb abort with status: %d",
+ ctx->label, _status);
+ }
+ 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_INFO,"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 check request (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;
+ assert(0);
+ ABORT(R_INTERNAL);
+ /* TODO(ekr@rtfm.com): Need to implement long-term auth for binding
+ requests */
+ 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_binding_request, &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_REQUEST:
+ if ((r=nr_stun_build_allocate_request(&ctx->auth_params, &ctx->params.allocate_request, &ctx->request)))
+ ABORT(r);
+ break;
+ case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
+ if ((r=nr_stun_build_refresh_request(&ctx->auth_params, &ctx->params.refresh_request, &ctx->request)))
+ ABORT(r);
+ break;
+ case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
+ if ((r=nr_stun_build_permission_request(&ctx->auth_params, &ctx->params.permission_request, &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;
+#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);
+
+ assert(ctx->my_addr.protocol==ctx->peer_addr.protocol);
+
+ if(r=nr_socket_sendto(ctx->sock, ctx->request->buffer, ctx->request->length, 0, &ctx->peer_addr)) {
+ if (r != R_WOULDBLOCK) {
+ ABORT(r);
+ }
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_socket_sendto blocked, treating as dropped packet",ctx->label);
+ }
+
+ 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) {
+ /* Reliable transport only get here once. Unreliable get here for
+ * their final timeout. */
+ ctx->timeout_ms += ctx->maximum_transmits_timeout_ms;
+ }
+ else if (ctx->timeout_ms) {
+ /* exponential backoff */
+ ctx->timeout_ms *= ctx->retransmission_backoff_factor;
+ }
+ else {
+ /* initial timeout unreliable transports */
+ ctx->timeout_ms = ctx->rto_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);
+
+ assert(ctx->timeout_ms);
+ NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle);
+ }
+
+ _status=0;
+ abort:
+ if (_status) {
+ nr_stun_client_failed(ctx);
+ }
+ 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_transport_addr_check(nr_transport_addr* addr, UINT4 check)
+ {
+ if((check & NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD) && nr_transport_addr_is_wildcard(addr))
+ return(R_BAD_DATA);
+
+ if ((check & NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK) && nr_transport_addr_is_loopback(addr))
+ return(R_BAD_DATA);
+
+ 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];
+ char *username = 0;
+ Data *password = 0;
+ int allow_unauthed_redirect = 0;
+ nr_stun_message_attribute *attr;
+ nr_transport_addr *mapped_addr = 0;
+ int fail_on_error = 0;
+ UCHAR hmac_key_d[16];
+ Data hmac_key;
+ int compute_lt_key=0;
+ /* TODO(bcampen@mozilla.com): Bug 1023619, refactor this. */
+ int response_matched=0;
+
+ ATTACH_DATA(hmac_key, hmac_key_d);
+
+ if ((ctx->state != NR_STUN_CLIENT_STATE_RUNNING) &&
+ (ctx->state != NR_STUN_CLIENT_STATE_WAITING))
+ ABORT(R_REJECTED);
+
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Inspecting STUN response (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:
+ /* If the STUN server responds with an error, give up, since we don't
+ * want to delay the completion of gathering. */
+ fail_on_error = 1;
+ compute_lt_key = 1;
+ /* Fall through */
+ 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:
+ /* If the STUN server responds with an error, give up, since we don't
+ * want to delay the completion of gathering. */
+ fail_on_error = 1;
+ break;
+
+ case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
+ /* If the STUN server responds with an error, give up, since we don't
+ * want to delay the completion of gathering. */
+ fail_on_error = 1;
+ break;
+
+#ifdef USE_ICE
+ case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
+ /* We do not set fail_on_error here. The error might be transient, and
+ * retrying isn't going to cause a slowdown. */
+ password = &ctx->params.ice_binding_request.password;
+ break;
+ case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
+ /* We do not set fail_on_error here. The error might be transient, and
+ * retrying isn't going to cause a slowdown. */
+ password = &ctx->params.ice_binding_request.password;
+ break;
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+ case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST:
+ fail_on_error = 1;
+ compute_lt_key = 1;
+ /* Do not require mutual auth on redirect responses to Allocate requests. */
+ allow_unauthed_redirect = 1;
+ username = ctx->auth_params.username;
+ password = &ctx->auth_params.password;
+ /* do nothing */
+ break;
+ case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
+ fail_on_error = 1;
+ compute_lt_key = 1;
+ username = ctx->auth_params.username;
+ password = &ctx->auth_params.password;
+ /* do nothing */
+ break;
+ case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
+ fail_on_error = 1;
+ compute_lt_key = 1;
+ username = ctx->auth_params.username;
+ password = &ctx->auth_params.password;
+ /* 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;
+ }
+
+ if (compute_lt_key) {
+ if (!ctx->realm || !username) {
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Long-term auth required but no realm/username specified. Randomizing key");
+ /* Fill the key with random bytes to guarantee non-match */
+ if (r=nr_crypto_random_bytes(hmac_key_d, sizeof(hmac_key_d)))
+ ABORT(r);
+ }
+ else {
+ if (r=nr_stun_compute_lt_message_integrity_password(username, ctx->realm,
+ password, &hmac_key))
+ ABORT(r);
+ }
+ password = &hmac_key;
+ }
+
+ if (ctx->response) {
+ nr_stun_message_destroy(&ctx->response);
+ }
+
+ /* TODO(bcampen@mozilla.com): Bug 1023619, refactor this. */
+ 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))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): error decoding response",ctx->label);
+ ABORT(r);
+ }
+
+ /* This will return an error if request and response don't match,
+ which is how we reject responses that match other contexts. */
+ if ((r=nr_stun_receive_message(ctx->request, ctx->response))) {
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Response is not for us",ctx->label);
+ ABORT(r);
+ }
+
+ r_log(NR_LOG_STUN,LOG_INFO,
+ "STUN-CLIENT(%s): Received response; processing",ctx->label);
+ response_matched=1;
+
+ if (allow_unauthed_redirect &&
+ nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_ERROR_CODE,
+ &attr) &&
+ (attr->u.error_code.number / 100 == 3)) {
+ password = 0;
+ }
+
+/* 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))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): long term auth failed",ctx->label);
+ ABORT(r);
+ }
+ }
+ else {
+ if ((r=nr_stun_receive_response_short_term_auth(ctx->response))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): short term auth failed",ctx->label);
+ ABORT(r);
+ }
+ }
+ }
+
+ if (NR_STUN_GET_TYPE_CLASS(ctx->response->header.type) == NR_CLASS_RESPONSE) {
+ if ((r=nr_stun_process_success_response(ctx->response))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_stun_process_success_response failed",ctx->label);
+ ABORT(r);
+ }
+ }
+ else {
+ if (fail_on_error) {
+ ctx->state = NR_STUN_CLIENT_STATE_FAILED;
+ }
+ /* Note: most times we call process_error_response, we get r != 0.
+
+ However, if the error is to be discarded, we get r == 0, smash
+ the error code, and just keep going.
+ */
+ if ((r=nr_stun_process_error_response(ctx->response, &ctx->error_code))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_stun_process_error_response failed",ctx->label);
+ ABORT(r);
+ }
+ else {
+ ctx->error_code = 0xffff;
+ /* drop the error on the floor */
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): processed error response",ctx->label);
+ ABORT(R_FAILED);
+ }
+ }
+
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Successfully parsed mode=%d",ctx->label,ctx->mode);
+
+/* TODO: !nn! this should be moved to individual message receive/processing sections */
+ switch (ctx->mode) {
+ case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
+ case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+
+ mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
+ break;
+
+ case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
+ if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0)) {
+ /* Compensate for a bug in Google's STUN servers where they always respond with MAPPED-ADDRESS */
+ r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS but MAPPED-ADDRESS. Falling back (though server is wrong).", ctx->label);
+ }
+ else {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS or MAPPED-ADDRESS",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+ }
+
+ mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
+ break;
+
+ case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0) && ! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MAPPED-ADDRESS",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+
+ mapped_addr = &ctx->results.stun_binding_response_stund_0_96.mapped_addr;
+ break;
+
+#ifdef USE_ICE
+ case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+
+ mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
+ break;
+ case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+
+ mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
+ break;
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+ case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST:
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+
+ if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_RELAY_ADDRESS, &attr)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-RELAYED-ADDRESS",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+
+ if ((r=nr_stun_transport_addr_check(&attr->u.relay_address.unmasked,
+ ctx->mapped_addr_check_mask))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_stun_transport_addr_check failed",ctx->label);
+ ABORT(r);
+ }
+
+ if ((r=nr_transport_addr_copy(
+ &ctx->results.allocate_response.relay_addr,
+ &attr->u.relay_address.unmasked))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_transport_addr_copy failed",ctx->label);
+ ABORT(r);
+ }
+
+ if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No LIFETIME",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+ ctx->results.allocate_response.lifetime_secs=attr->u.lifetime_secs;
+
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received relay address: %s", ctx->label, ctx->results.allocate_response.relay_addr.as_string);
+
+ mapped_addr = &ctx->results.allocate_response.mapped_addr;
+
+ break;
+ case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+ if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No LIFETIME",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+ ctx->results.refresh_response.lifetime_secs=attr->u.lifetime_secs;
+ break;
+ case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
+ if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+ break;
+#endif /* USE_TURN */
+
+ default:
+ assert(0);
+ ABORT(R_FAILED);
+ break;
+ }
+
+ /* make sure we have the most up-to-date address from this peer */
+ if (nr_transport_addr_cmp(&ctx->peer_addr, peer_addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
+ r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Peer moved from %s to %s", ctx->label, ctx->peer_addr.as_string, peer_addr->as_string);
+ nr_transport_addr_copy(&ctx->peer_addr, peer_addr);
+ }
+
+ if (mapped_addr) {
+ if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, &attr)) {
+ if ((r=nr_stun_transport_addr_check(&attr->u.xor_mapped_address.unmasked,
+ ctx->mapped_addr_check_mask))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): XOR-MAPPED-ADDRESS is bogus",ctx->label);
+ ABORT(r);
+ }
+
+ if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.xor_mapped_address.unmasked))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_transport_addr_copy failed",ctx->label);
+ ABORT(r);
+ }
+ }
+ else if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, &attr)) {
+ if ((r=nr_stun_transport_addr_check(&attr->u.mapped_address,
+ ctx->mapped_addr_check_mask))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): MAPPED-ADDRESS is bogus",ctx->label);
+ ABORT(r);
+ }
+
+ if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.mapped_address))) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_transport_addr_copy failed",ctx->label);
+ ABORT(r);
+ }
+ }
+ else {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No mapped address!",ctx->label);
+ ABORT(R_BAD_DATA);
+ }
+
+ // STUN doesn't distinguish protocol in mapped address, therefore
+ // assign used protocol from peer_addr
+ if (mapped_addr->protocol!=peer_addr->protocol){
+ mapped_addr->protocol=peer_addr->protocol;
+ nr_transport_addr_fmt_addr_string(mapped_addr);
+ }
+
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received mapped address: %s", ctx->label, mapped_addr->as_string);
+ }
+
+ ctx->state=NR_STUN_CLIENT_STATE_DONE;
+
+ _status=0;
+ abort:
+ if(_status && response_matched){
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): Error processing response: %s, stun error code %d.", ctx->label, nr_strerror(_status), (int)ctx->error_code);
+ }
+
+ if ((ctx->state != NR_STUN_CLIENT_STATE_RUNNING) &&
+ (ctx->state != NR_STUN_CLIENT_STATE_WAITING)) {
+ /* Cancel the timer firing */
+ if (ctx->timer_handle) {
+ NR_async_timer_cancel(ctx->timer_handle);
+ ctx->timer_handle = 0;
+ }
+
+ nr_stun_client_fire_finished_cb(ctx);
+ }
+
+ return(_status);
+ }
+
+int nr_stun_client_ctx_destroy(nr_stun_client_ctx **ctxp)
+ {
+ nr_stun_client_ctx *ctx;
+
+ if(!ctxp || !*ctxp)
+ return(0);
+
+ ctx=*ctxp;
+ *ctxp=0;
+
+ nr_stun_client_reset(ctx);
+
+ RFREE(ctx->nonce);
+ RFREE(ctx->realm);
+
+ RFREE(ctx->label);
+ RFREE(ctx);
+
+ return(0);
+ }
+
+
+int nr_stun_client_cancel(nr_stun_client_ctx *ctx)
+ {
+ /* Cancel the timer firing */
+ if (ctx->timer_handle){
+ NR_async_timer_cancel(ctx->timer_handle);
+ ctx->timer_handle=0;
+ }
+
+ /* Mark cancelled so we ignore any returned messsages */
+ ctx->state=NR_STUN_CLIENT_STATE_CANCELLED;
+ return(0);
+}
+
+int nr_stun_client_wait(nr_stun_client_ctx *ctx)
+ {
+ nr_stun_client_cancel(ctx);
+ ctx->state=NR_STUN_CLIENT_STATE_WAITING;
+
+ ctx->request_ct = ctx->maximum_transmits;
+ ctx->timeout_ms = ctx->maximum_transmits_timeout_ms;
+ NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle);
+
+ return(0);
+ }
+
+int nr_stun_client_failed(nr_stun_client_ctx *ctx)
+ {
+ nr_stun_client_cancel(ctx);
+ ctx->state=NR_STUN_CLIENT_STATE_FAILED;
+ nr_stun_client_fire_finished_cb(ctx);
+ return(0);
+ }
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_client_ctx.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_client_ctx.h
new file mode 100644
index 0000000000..0cc9045e2a
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_client_ctx.h
@@ -0,0 +1,200 @@
+/*
+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_client_ctx_h
+#define _stun_client_ctx_h
+
+/* forward declaration */
+typedef struct nr_stun_client_ctx_ nr_stun_client_ctx;
+
+#include "stun.h"
+
+/* Checklist for adding new STUN transaction types
+
+ 1. Add new method type in stun.h (NR_METHOD_*)
+ 2. Add new MSGs in stun.h (NR_STUN_MSG_*)
+ 3. Add new messages to stun_util.c:nr_stun_msg_type
+ 4. Add new request type to stun_build.h
+ 4. Add new message builder to stun_build.c
+ 5. Add new response type to stun_client_ctx.h
+ 6. Add new arm to stun_client_ctx.c:nr_stun_client_send_request
+ 7. Add new arms to nr_stun_client_process_response
+ 8. Add new arms to stun_hint.c:nr_is_stun_message
+*/
+
+
+
+
+typedef union nr_stun_client_params_ {
+
+ nr_stun_client_stun_binding_request_params stun_binding_request;
+ nr_stun_client_stun_keepalive_params stun_keepalive;
+#ifdef USE_STUND_0_96
+ nr_stun_client_stun_binding_request_stund_0_96_params stun_binding_request_stund_0_96;
+#endif /* USE_STUND_0_96 */
+
+#ifdef USE_ICE
+ nr_stun_client_ice_binding_request_params ice_binding_request;
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+ nr_stun_client_allocate_request_params allocate_request;
+ nr_stun_client_refresh_request_params refresh_request;
+ nr_stun_client_permission_request_params permission_request;
+ nr_stun_client_send_indication_params send_indication;
+#endif /* USE_TURN */
+
+} nr_stun_client_params;
+
+typedef struct nr_stun_client_stun_binding_response_results_ {
+ nr_transport_addr mapped_addr;
+} nr_stun_client_stun_binding_response_results;
+
+typedef struct nr_stun_client_stun_binding_response_stund_0_96_results_ {
+ nr_transport_addr mapped_addr;
+} nr_stun_client_stun_binding_response_stund_0_96_results;
+
+#ifdef USE_ICE
+typedef struct nr_stun_client_ice_use_candidate_results_ {
+#ifdef WIN32 // silly VC++ gives error if no members
+ int dummy;
+#endif
+} nr_stun_client_ice_use_candidate_results;
+
+typedef struct nr_stun_client_ice_binding_response_results_ {
+ nr_transport_addr mapped_addr;
+} nr_stun_client_ice_binding_response_results;
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+typedef struct nr_stun_client_allocate_response_results_ {
+ nr_transport_addr relay_addr;
+ nr_transport_addr mapped_addr;
+ UINT4 lifetime_secs;
+} nr_stun_client_allocate_response_results;
+
+typedef struct nr_stun_client_refresh_response_results_ {
+ UINT4 lifetime_secs;
+} nr_stun_client_refresh_response_results;
+
+typedef struct nr_stun_client_permission_response_results_ {
+ UINT4 lifetime_secs;
+} nr_stun_client_permission_response_results;
+
+#endif /* USE_TURN */
+
+typedef union nr_stun_client_results_ {
+ nr_stun_client_stun_binding_response_results stun_binding_response;
+ nr_stun_client_stun_binding_response_stund_0_96_results stun_binding_response_stund_0_96;
+
+#ifdef USE_ICE
+ nr_stun_client_ice_use_candidate_results ice_use_candidate;
+ nr_stun_client_ice_binding_response_results ice_binding_response;
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+ nr_stun_client_allocate_response_results allocate_response;
+ nr_stun_client_refresh_response_results refresh_response;
+#endif /* USE_TURN */
+} nr_stun_client_results;
+
+struct nr_stun_client_ctx_ {
+ int state;
+#define NR_STUN_CLIENT_STATE_INITTED 0
+#define NR_STUN_CLIENT_STATE_RUNNING 1
+#define NR_STUN_CLIENT_STATE_DONE 2
+#define NR_STUN_CLIENT_STATE_FAILED 3
+#define NR_STUN_CLIENT_STATE_TIMED_OUT 4
+#define NR_STUN_CLIENT_STATE_CANCELLED 5
+#define NR_STUN_CLIENT_STATE_WAITING 6
+
+ int mode;
+#define NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH 1
+#define NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH 2
+#define NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH 3
+#define NR_STUN_CLIENT_MODE_KEEPALIVE 4
+#define NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96 5
+#ifdef USE_ICE
+#define NR_ICE_CLIENT_MODE_USE_CANDIDATE 10
+#define NR_ICE_CLIENT_MODE_BINDING_REQUEST 11
+#endif /* USE_ICE */
+#ifdef USE_TURN
+#define NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST 20
+#define NR_TURN_CLIENT_MODE_REFRESH_REQUEST 21
+#define NR_TURN_CLIENT_MODE_SEND_INDICATION 22
+#define NR_TURN_CLIENT_MODE_DATA_INDICATION 24
+#define NR_TURN_CLIENT_MODE_PERMISSION_REQUEST 25
+#endif /* USE_TURN */
+
+ char *label;
+ nr_transport_addr my_addr;
+ nr_transport_addr peer_addr;
+ nr_socket *sock;
+ nr_stun_client_auth_params auth_params;
+ nr_stun_client_params params;
+ nr_stun_client_results results;
+ char *nonce;
+ char *realm;
+ void *timer_handle;
+ UINT2 request_ct;
+ UINT2 retransmit_ct;
+ UINT4 rto_ms; /* retransmission time out */
+ double retransmission_backoff_factor;
+ UINT4 maximum_transmits;
+ UINT4 maximum_transmits_timeout_ms;
+ UINT4 mapped_addr_check_mask; /* What checks to run on mapped addresses */
+ int timeout_ms;
+ struct timeval timer_set;
+ NR_async_cb finished_cb;
+ void *cb_arg;
+ nr_stun_message *request;
+ nr_stun_message *response;
+ UINT2 error_code;
+};
+
+int nr_stun_client_ctx_create(char *label, nr_socket *sock, nr_transport_addr *peer, UINT4 RTO, nr_stun_client_ctx **ctxp);
+int nr_stun_client_start(nr_stun_client_ctx *ctx, int mode, NR_async_cb finished_cb, void *cb_arg);
+int nr_stun_client_restart(nr_stun_client_ctx* ctx,
+ const nr_transport_addr* peer_addr);
+int nr_stun_client_force_retransmit(nr_stun_client_ctx *ctx);
+int nr_stun_client_reset(nr_stun_client_ctx *ctx);
+int nr_stun_client_ctx_destroy(nr_stun_client_ctx **ctxp);
+int nr_stun_transport_addr_check(nr_transport_addr* addr, UINT4 mask);
+int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr);
+int nr_stun_client_cancel(nr_stun_client_ctx *ctx);
+int nr_stun_client_wait(nr_stun_client_ctx *ctx);
+int nr_stun_client_failed(nr_stun_client_ctx *ctx);
+
+#endif
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.c
new file mode 100644
index 0000000000..ae748a667b
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.c
@@ -0,0 +1,1550 @@
+/*
+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.
+*/
+
+#include <errno.h>
+#include <csi_platform.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <stdlib.h>
+#include <io.h>
+#include <time.h>
+#else /* UNIX */
+#include <string.h>
+#endif /* end UNIX */
+#include <assert.h>
+#include <stddef.h>
+
+#include "nr_api.h"
+#include "stun.h"
+#include "byteorder.h"
+#include "r_crc32.h"
+#include "nr_crypto.h"
+
+#define NR_STUN_IPV4_FAMILY 0x01
+#define NR_STUN_IPV6_FAMILY 0x02
+
+#define SKIP_ATTRIBUTE_DECODE -1
+
+static int nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info);
+
+static int nr_stun_fix_attribute_ordering(nr_stun_message *msg);
+
+static int nr_stun_encode_htons(UINT2 data, size_t buflen, UCHAR *buf, size_t *offset);
+static int nr_stun_encode_htonl(UINT4 data, size_t buflen, UCHAR *buf, size_t *offset);
+static int nr_stun_encode_htonll(UINT8 data, size_t buflen, UCHAR *buf, size_t *offset);
+static int nr_stun_encode(UCHAR *data, size_t length, size_t buflen, UCHAR *buf, size_t *offset);
+
+static int nr_stun_decode_htons(UCHAR *buf, size_t buflen, size_t *offset, UINT2 *data);
+static int nr_stun_decode_htonl(UCHAR *buf, size_t buflen, size_t *offset, UINT4 *data);
+static int nr_stun_decode_htonll(UCHAR *buf, size_t buflen, size_t *offset, UINT8 *data);
+static int nr_stun_decode(size_t length, UCHAR *buf, size_t buflen, size_t *offset, UCHAR *data);
+
+static int nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, size_t len, void *data, size_t max_bytes, size_t max_chars);
+
+static int nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
+static int nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
+static int nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
+static int nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
+static int nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
+static int
+nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data);
+
+
+int
+nr_stun_encode_htons(UINT2 data, size_t buflen, UCHAR *buf, size_t *offset)
+{
+ UINT2 d = htons(data);
+
+ if (*offset + sizeof(d) >= buflen) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd >= %d", *offset, sizeof(d), buflen);
+ return R_BAD_DATA;
+ }
+
+ memcpy(&buf[*offset], &d, sizeof(d));
+ *offset += sizeof(d);
+
+ return 0;
+}
+
+int
+nr_stun_encode_htonl(UINT4 data, size_t buflen, UCHAR *buf, size_t *offset)
+{
+ UINT4 d = htonl(data);
+
+ if (*offset + sizeof(d) > buflen) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
+ return R_BAD_DATA;
+ }
+
+ memcpy(&buf[*offset], &d, sizeof(d));
+ *offset += sizeof(d);
+
+ return 0;
+}
+
+int
+nr_stun_encode_htonll(UINT8 data, size_t buflen, UCHAR *buf, size_t *offset)
+{
+ UINT8 d = nr_htonll(data);
+
+ if (*offset + sizeof(d) > buflen) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
+ return R_BAD_DATA;
+ }
+
+ memcpy(&buf[*offset], &d, sizeof(d));
+ *offset += sizeof(d);
+
+ return 0;
+}
+
+int
+nr_stun_encode(UCHAR *data, size_t length, size_t buflen, UCHAR *buf, size_t *offset)
+{
+ if (*offset + length > buflen) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %d > %d", *offset, length, buflen);
+ return R_BAD_DATA;
+ }
+
+ memcpy(&buf[*offset], data, length);
+ *offset += length;
+
+ return 0;
+}
+
+
+int
+nr_stun_decode_htons(UCHAR *buf, size_t buflen, size_t *offset, UINT2 *data)
+{
+ UINT2 d;
+
+ if (*offset + sizeof(d) > buflen) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
+ return R_BAD_DATA;
+ }
+
+ memcpy(&d, &buf[*offset], sizeof(d));
+ *offset += sizeof(d);
+ *data = htons(d);
+
+ return 0;
+}
+
+int
+nr_stun_decode_htonl(UCHAR *buf, size_t buflen, size_t *offset, UINT4 *data)
+{
+ UINT4 d;
+
+ if (*offset + sizeof(d) > buflen) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
+ return R_BAD_DATA;
+ }
+
+ memcpy(&d, &buf[*offset], sizeof(d));
+ *offset += sizeof(d);
+ *data = htonl(d);
+
+ return 0;
+}
+
+int
+nr_stun_decode_htonll(UCHAR *buf, size_t buflen, size_t *offset, UINT8 *data)
+{
+ UINT8 d;
+
+ if (*offset + sizeof(d) > buflen) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
+ return R_BAD_DATA;
+ }
+
+ memcpy(&d, &buf[*offset], sizeof(d));
+ *offset += sizeof(d);
+ *data = nr_htonll(d);
+
+ return 0;
+}
+
+int
+nr_stun_decode(size_t length, UCHAR *buf, size_t buflen, size_t *offset, UCHAR *data)
+{
+ if (*offset + length > buflen) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %d > %d", *offset, length, buflen);
+ return R_BAD_DATA;
+ }
+
+ memcpy(data, &buf[*offset], length);
+ *offset += length;
+
+ return 0;
+}
+
+/**
+ * The argument must be a non-null pointer to a zero-terminated string.
+ *
+ * If the argument is valid UTF-8, returns the number of code points in the
+ * string excluding the zero-terminator.
+ *
+ * If the argument is invalid UTF-8, returns a lower bound for the number of
+ * code points in the string. (If UTF-8 error handling was performed on the
+ * string, new REPLACEMENT CHARACTER code points could be introduced in
+ * a way that would increase the total number of code points compared to
+ * what this function counts.)
+ */
+size_t
+nr_count_utf8_code_points_without_validation(const char *s) {
+ size_t nchars = 0;
+ char c;
+ while ((c = *s)) {
+ if ((c & 0xC0) != 0x80) {
+ ++nchars;
+ }
+ ++s;
+ }
+ return nchars;
+}
+
+int
+nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, size_t len, void *data, size_t max_bytes, size_t max_chars)
+{
+ int _status;
+ char *s = data;
+ size_t nchars;
+
+ if (len > max_bytes) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "%s is too large: %d bytes", attr_info->name, len);
+ ABORT(R_FAILED);
+ }
+
+ nchars = nr_count_utf8_code_points_without_validation(s);
+ if (nchars > max_chars) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "%s is too large: %zd characters", attr_info->name, nchars);
+ ABORT(R_FAILED);
+ }
+
+ _status = 0;
+ abort:
+ return _status;
+}
+
+int
+nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
+{
+ int r,_status;
+ nr_stun_attr_error_code *ec = data;
+
+ if (ec->number < 300 || ec->number > 699)
+ ABORT(R_FAILED);
+
+ if ((r=nr_stun_attr_string_illegal(attr_info, strlen(ec->reason), ec->reason, NR_STUN_MAX_ERROR_CODE_REASON_BYTES, NR_STUN_MAX_ERROR_CODE_REASON_CHARS)))
+ ABORT(r);
+
+ _status = 0;
+ abort:
+ return _status;
+}
+
+int
+nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
+{
+ return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_NONCE_BYTES, NR_STUN_MAX_NONCE_CHARS);
+}
+
+int
+nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
+{
+ return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_REALM_BYTES, NR_STUN_MAX_REALM_CHARS);
+}
+
+int
+nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
+{
+ return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_SERVER_BYTES, NR_STUN_MAX_SERVER_CHARS);
+}
+
+int
+nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, size_t attrlen, void *data)
+{
+ return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_USERNAME_BYTES, -1);
+}
+
+static int
+nr_stun_attr_codec_UCHAR_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %u", msg, attr_info->name, *(UCHAR*)data);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_UCHAR_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ int start = offset;
+ UINT4 tmp = *((UCHAR *)data);
+ tmp <<= 24;
+
+ if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
+ || nr_stun_encode_htons(sizeof(UINT4) , buflen, buf, &offset)
+ || nr_stun_encode_htonl(tmp , buflen, buf, &offset))
+ return R_FAILED;
+
+ *attrlen = offset - start;
+
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_UCHAR_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ UINT4 tmp;
+
+ if (attrlen != sizeof(UINT4)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen);
+ return R_FAILED;
+ }
+
+ if (nr_stun_decode_htonl(buf, buflen, &offset, &tmp))
+ return R_FAILED;
+
+ *((UCHAR *)data) = (tmp >> 24) & 0xff;
+
+ return 0;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_UCHAR = {
+ "UCHAR",
+ nr_stun_attr_codec_UCHAR_print,
+ nr_stun_attr_codec_UCHAR_encode,
+ nr_stun_attr_codec_UCHAR_decode
+};
+
+static int
+nr_stun_attr_codec_UINT4_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %u", msg, attr_info->name, *(UINT4*)data);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_UINT4_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ int start = offset;
+
+ if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
+ || nr_stun_encode_htons(sizeof(UINT4) , buflen, buf, &offset)
+ || nr_stun_encode_htonl(*(UINT4*)data , buflen, buf, &offset))
+ return R_FAILED;
+
+ *attrlen = offset - start;
+
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_UINT4_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ if (attrlen != sizeof(UINT4)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen);
+ return R_FAILED;
+ }
+
+ if (nr_stun_decode_htonl(buf, buflen, &offset, (UINT4*)data))
+ return R_FAILED;
+
+ return 0;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_UINT4 = {
+ "UINT4",
+ nr_stun_attr_codec_UINT4_print,
+ nr_stun_attr_codec_UINT4_encode,
+ nr_stun_attr_codec_UINT4_decode
+};
+
+static int
+nr_stun_attr_codec_UINT8_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %llu", msg, attr_info->name, *(UINT8*)data);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_UINT8_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ int start = offset;
+
+ if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
+ || nr_stun_encode_htons(sizeof(UINT8) , buflen, buf, &offset)
+ || nr_stun_encode_htonll(*(UINT8*)data , buflen, buf, &offset))
+ return R_FAILED;
+
+ *attrlen = offset - start;
+
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_UINT8_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ if (attrlen != sizeof(UINT8)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen);
+ return R_FAILED;
+ }
+
+ if (nr_stun_decode_htonll(buf, buflen, &offset, (UINT8*)data))
+ return R_FAILED;
+
+ return 0;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_UINT8 = {
+ "UINT8",
+ nr_stun_attr_codec_UINT8_print,
+ nr_stun_attr_codec_UINT8_encode,
+ nr_stun_attr_codec_UINT8_decode
+};
+
+static int
+nr_stun_attr_codec_addr_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s", msg, attr_info->name, ((nr_transport_addr*)data)->as_string);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_addr_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ int r,_status;
+ int start = offset;
+ nr_transport_addr *addr = data;
+ UCHAR pad = '\0';
+ UCHAR family;
+
+ if ((r=nr_stun_encode_htons(attr_info->type, buflen, buf, &offset)))
+ ABORT(r);
+
+ switch (addr->ip_version) {
+ case NR_IPV4:
+ family = NR_STUN_IPV4_FAMILY;
+ if (nr_stun_encode_htons(8 , buflen, buf, &offset)
+ || nr_stun_encode(&pad, 1 , buflen, buf, &offset)
+ || nr_stun_encode(&family, 1 , buflen, buf, &offset)
+ || nr_stun_encode_htons(ntohs(addr->u.addr4.sin_port), buflen, buf, &offset)
+ || nr_stun_encode_htonl(ntohl(addr->u.addr4.sin_addr.s_addr), buflen, buf, &offset))
+ ABORT(R_FAILED);
+ break;
+
+ case NR_IPV6:
+ family = NR_STUN_IPV6_FAMILY;
+ if (nr_stun_encode_htons(20 , buflen, buf, &offset)
+ || nr_stun_encode(&pad, 1 , buflen, buf, &offset)
+ || nr_stun_encode(&family, 1 , buflen, buf, &offset)
+ || nr_stun_encode_htons(ntohs(addr->u.addr6.sin6_port), buflen, buf, &offset)
+ || nr_stun_encode(addr->u.addr6.sin6_addr.s6_addr, 16, buflen, buf, &offset))
+ ABORT(R_FAILED);
+ break;
+
+ default:
+ assert(0);
+ ABORT(R_INTERNAL);
+ break;
+ }
+
+ *attrlen = offset - start;
+
+ _status = 0;
+ abort:
+ return _status;
+}
+
+static int
+nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ int _status;
+ UCHAR pad;
+ UCHAR family;
+ UINT2 port;
+ UINT4 addr4;
+ struct in6_addr addr6;
+ nr_transport_addr *result = data;
+
+ if (nr_stun_decode(1, buf, buflen, &offset, &pad)
+ || nr_stun_decode(1, buf, buflen, &offset, &family))
+ ABORT(R_FAILED);
+
+ switch (family) {
+ case NR_STUN_IPV4_FAMILY:
+ if (attrlen != 8) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Illegal attribute length: %d", attrlen);
+ ABORT(R_FAILED);
+ }
+
+ if (nr_stun_decode_htons(buf, buflen, &offset, &port)
+ || nr_stun_decode_htonl(buf, buflen, &offset, &addr4))
+ ABORT(R_FAILED);
+
+ if (nr_ip4_port_to_transport_addr(addr4, port, IPPROTO_UDP, result))
+ ABORT(R_FAILED);
+ break;
+
+ case NR_STUN_IPV6_FAMILY:
+ if (attrlen != 20) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Illegal attribute length: %d", attrlen);
+ ABORT(R_FAILED);
+ }
+
+ if (nr_stun_decode_htons(buf, buflen, &offset, &port)
+ || nr_stun_decode(16, buf, buflen, &offset, addr6.s6_addr))
+ ABORT(R_FAILED);
+
+ if (nr_ip6_port_to_transport_addr(&addr6, port, IPPROTO_UDP, result))
+ ABORT(R_FAILED);
+ break;
+
+ default:
+ r_log(NR_LOG_STUN, LOG_WARNING, "Illegal address family: %d", family);
+ ABORT(R_FAILED);
+ break;
+ }
+
+ _status = 0;
+ abort:
+ return _status;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_addr = {
+ "addr",
+ nr_stun_attr_codec_addr_print,
+ nr_stun_attr_codec_addr_encode,
+ nr_stun_attr_codec_addr_decode
+};
+
+static int
+nr_stun_attr_codec_data_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ nr_stun_attr_data *d = data;
+ r_dump(NR_LOG_STUN, LOG_DEBUG, attr_info->name, (char*)d->data, d->length);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_data_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ nr_stun_attr_data *d = data;
+ int start = offset;
+
+ if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
+ || nr_stun_encode_htons(d->length , buflen, buf, &offset)
+ || nr_stun_encode(d->data, d->length , buflen, buf, &offset))
+ return R_FAILED;
+
+ *attrlen = offset - start;
+
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_data_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ int _status;
+ nr_stun_attr_data *result = data;
+
+ /* -1 because it is going to be null terminated just to be safe */
+ if (attrlen >= (sizeof(result->data) - 1)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Too much data: %d bytes", attrlen);
+ ABORT(R_FAILED);
+ }
+
+ if (nr_stun_decode(attrlen, buf, buflen, &offset, result->data))
+ ABORT(R_FAILED);
+
+ result->length = attrlen;
+ result->data[attrlen] = '\0'; /* just to be nice */
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_data = {
+ "data",
+ nr_stun_attr_codec_data_print,
+ nr_stun_attr_codec_data_encode,
+ nr_stun_attr_codec_data_decode
+};
+
+static int
+nr_stun_attr_codec_error_code_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ nr_stun_attr_error_code *error_code = data;
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %d %s",
+ msg, attr_info->name, error_code->number,
+ error_code->reason);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_error_code_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ nr_stun_attr_error_code *error_code = data;
+ int start = offset;
+ int length = strlen(error_code->reason);
+ UCHAR pad[2] = { 0 };
+ UCHAR class = error_code->number / 100;
+ UCHAR number = error_code->number % 100;
+
+ if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
+ || nr_stun_encode_htons(4 + length , buflen, buf, &offset)
+ || nr_stun_encode(pad, 2 , buflen, buf, &offset)
+ || nr_stun_encode(&class, 1 , buflen, buf, &offset)
+ || nr_stun_encode(&number, 1 , buflen, buf, &offset)
+ || nr_stun_encode((UCHAR*)error_code->reason, length, buflen, buf, &offset))
+ return R_FAILED;
+
+ *attrlen = offset - start;
+
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_error_code_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ int _status;
+ nr_stun_attr_error_code *result = data;
+ UCHAR pad[2];
+ UCHAR class;
+ UCHAR number;
+ size_t size_reason;
+
+ if (nr_stun_decode(2, buf, buflen, &offset, pad)
+ || nr_stun_decode(1, buf, buflen, &offset, &class)
+ || nr_stun_decode(1, buf, buflen, &offset, &number))
+ ABORT(R_FAILED);
+
+ result->number = (class * 100) + number;
+
+ size_reason = attrlen - 4;
+
+ /* -1 because the string will be null terminated */
+ if (size_reason > (sizeof(result->reason) - 1)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Reason is too large, truncating");
+ /* don't fail, but instead truncate the reason */
+ size_reason = sizeof(result->reason) - 1;
+ }
+
+ if (nr_stun_decode(size_reason, buf, buflen, &offset, (UCHAR*)result->reason))
+ ABORT(R_FAILED);
+ result->reason[size_reason] = '\0';
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_error_code = {
+ "error_code",
+ nr_stun_attr_codec_error_code_print,
+ nr_stun_attr_codec_error_code_encode,
+ nr_stun_attr_codec_error_code_decode
+};
+
+static int
+nr_stun_attr_codec_fingerprint_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ nr_stun_attr_fingerprint *fingerprint = data;
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %08x", msg, attr_info->name, fingerprint->checksum);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_fingerprint_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ UINT4 checksum;
+ nr_stun_attr_fingerprint *fingerprint = data;
+ nr_stun_message_header *header = (nr_stun_message_header*)buf;
+
+ /* the length must include the FINGERPRINT attribute when computing
+ * the fingerprint */
+ header->length = ntohs(header->length);
+ header->length += 8; /* Fingerprint */
+ header->length = htons(header->length);
+
+ if (r_crc32((char*)buf, offset, &checksum)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Unable to compute fingerprint");
+ return R_FAILED;
+ }
+
+ fingerprint->checksum = checksum ^ 0x5354554e;
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Computed FINGERPRINT %08x", fingerprint->checksum);
+
+ fingerprint->valid = 1;
+ return nr_stun_attr_codec_UINT4.encode(attr_info, &fingerprint->checksum, offset, buflen, buf, attrlen);
+}
+
+static int
+nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ int r,_status;
+ nr_stun_attr_fingerprint *fingerprint = data;
+ nr_stun_message_header *header = (nr_stun_message_header*)buf;
+ size_t length;
+ UINT4 checksum;
+
+ if ((r=nr_stun_attr_codec_UINT4.decode(attr_info, attrlen, buf, offset, buflen, &fingerprint->checksum)))
+ ABORT(r);
+
+ offset -= 4; /* rewind to before the length and type fields */
+
+ /* the length must include the FINGERPRINT attribute when computing
+ * the fingerprint */
+ length = offset; /* right before FINGERPRINT */
+ length -= sizeof(*header); /* remove header length */
+ length += 8; /* add length of Fingerprint */
+ header->length = htons(length);
+
+ /* make sure FINGERPRINT is final attribute in message */
+ if (length + sizeof(*header) != buflen) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Fingerprint is not final attribute in message");
+ ABORT(R_FAILED);
+ }
+
+ if (r_crc32((char*)buf, offset, &checksum)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Unable to compute fingerprint");
+ ABORT(R_FAILED);
+ }
+
+ fingerprint->valid = (fingerprint->checksum == (checksum ^ 0x5354554e));
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Computed FINGERPRINT %08x", (checksum ^ 0x5354554e));
+ if (! fingerprint->valid)
+ r_log(NR_LOG_STUN, LOG_WARNING, "Invalid FINGERPRINT %08x", fingerprint->checksum);
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_fingerprint = {
+ "fingerprint",
+ nr_stun_attr_codec_fingerprint_print,
+ nr_stun_attr_codec_fingerprint_encode,
+ nr_stun_attr_codec_fingerprint_decode
+};
+
+static int
+nr_stun_attr_codec_flag_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: on", msg, attr_info->name);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_flag_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ int start = offset;
+
+ if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
+ || nr_stun_encode_htons(0 , buflen, buf, &offset))
+ return R_FAILED;
+
+ *attrlen = offset - start;
+
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_flag_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ if (attrlen != 0) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Illegal flag length: %d", attrlen);
+ return R_FAILED;
+ }
+
+ return 0;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_flag = {
+ "flag",
+ nr_stun_attr_codec_flag_print,
+ nr_stun_attr_codec_flag_encode,
+ nr_stun_attr_codec_flag_decode
+};
+
+static int
+nr_stun_attr_codec_message_integrity_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ nr_stun_attr_message_integrity *integrity = data;
+ r_dump(NR_LOG_STUN, LOG_DEBUG, attr_info->name, (char*)integrity->hash, sizeof(integrity->hash));
+ return 0;
+}
+
+static int
+nr_stun_compute_message_integrity(UCHAR *buf, int offset, UCHAR *password, int passwordlen, UCHAR *computedHMAC)
+{
+ int r,_status;
+ UINT2 hold;
+ UINT2 length;
+ nr_stun_message_header *header;
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Computing MESSAGE-INTEGRITY");
+
+ header = (nr_stun_message_header*)buf;
+ hold = header->length;
+
+ /* adjust the length of the message */
+ length = offset;
+ length -= sizeof(*header);
+ length += 24; /* for MESSAGE-INTEGRITY attribute */
+ header->length = htons(length);
+
+ if ((r=nr_crypto_hmac_sha1((UCHAR*)password, passwordlen,
+ buf, offset, computedHMAC)))
+ ABORT(r);
+
+ r_dump(NR_LOG_STUN, LOG_DEBUG, "Computed MESSAGE-INTEGRITY ", (char*)computedHMAC, 20);
+
+ _status=0;
+ abort:
+ header->length = hold;
+ return _status;
+}
+
+static int
+nr_stun_attr_codec_message_integrity_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ int start = offset;
+ nr_stun_attr_message_integrity *integrity = data;
+
+ if (nr_stun_compute_message_integrity(buf, offset, integrity->password, integrity->passwordlen, integrity->hash))
+ return R_FAILED;
+
+ if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
+ || nr_stun_encode_htons(sizeof(integrity->hash) , buflen, buf, &offset)
+ || nr_stun_encode(integrity->hash, sizeof(integrity->hash) , buflen, buf, &offset))
+ return R_FAILED;
+
+ *attrlen = offset - start;
+
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_message_integrity_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ int _status;
+ int start;
+ nr_stun_attr_message_integrity *result = data;
+ UCHAR computedHMAC[20];
+
+ result->valid = 0;
+
+ if (attrlen != 20) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "%s must be 20 bytes, not %d", attr_info->name, attrlen);
+ ABORT(R_FAILED);
+ }
+
+ start = offset - 4; /* rewind to before the length and type fields */
+ if (start < 0)
+ ABORT(R_INTERNAL);
+
+ if (nr_stun_decode(attrlen, buf, buflen, &offset, result->hash))
+ ABORT(R_FAILED);
+
+ if (result->unknown_user) {
+ result->valid = 0;
+ }
+ else {
+ if (nr_stun_compute_message_integrity(buf, start, result->password, result->passwordlen, computedHMAC))
+ ABORT(R_FAILED);
+
+ assert(sizeof(computedHMAC) == sizeof(result->hash));
+
+ result->valid = (memcmp(computedHMAC, result->hash, 20) == 0);
+ }
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_message_integrity = {
+ "message_integrity",
+ nr_stun_attr_codec_message_integrity_print,
+ nr_stun_attr_codec_message_integrity_encode,
+ nr_stun_attr_codec_message_integrity_decode
+};
+
+static int
+nr_stun_attr_codec_noop_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ return SKIP_ATTRIBUTE_DECODE;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_noop = {
+ "NOOP",
+ 0, /* ignore, never print these attributes */
+ 0, /* ignore, never encode these attributes */
+ nr_stun_attr_codec_noop_decode
+};
+
+static int
+nr_stun_attr_codec_quoted_string_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s",
+ msg, attr_info->name, (char*)data);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_quoted_string_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+//TODO: !nn! syntax check, conversion if not quoted already?
+//We'll just restrict this in the API -- EKR
+ return nr_stun_attr_codec_string.encode(attr_info, data, offset, buflen, buf, attrlen);
+}
+
+static int
+nr_stun_attr_codec_quoted_string_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+//TODO: !nn! I don't see any need to unquote this but we may
+//find one later -- EKR
+ return nr_stun_attr_codec_string.decode(attr_info, attrlen, buf, offset, buflen, data);
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_quoted_string = {
+ "quoted_string",
+ nr_stun_attr_codec_quoted_string_print,
+ nr_stun_attr_codec_quoted_string_encode,
+ nr_stun_attr_codec_quoted_string_decode
+};
+
+static int
+nr_stun_attr_codec_string_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s",
+ msg, attr_info->name, (char*)data);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_string_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ int start = offset;
+ char *str = data;
+ int length = strlen(str);
+
+ if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
+ || nr_stun_encode_htons(length , buflen, buf, &offset)
+ || nr_stun_encode((UCHAR*)str, length , buflen, buf, &offset))
+ return R_FAILED;
+
+ *attrlen = offset - start;
+
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_string_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ int _status;
+ char *result = data;
+
+ /* actual enforcement of the specific string size happens elsewhere */
+ if (attrlen >= NR_STUN_MAX_STRING_SIZE) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "String is too large: %d bytes", attrlen);
+ ABORT(R_FAILED);
+ }
+
+ if (nr_stun_decode(attrlen, buf, buflen, &offset, (UCHAR*)result))
+ ABORT(R_FAILED);
+ result[attrlen] = '\0'; /* just to be nice */
+
+ if (strlen(result) != attrlen) {
+ /* stund 0.96 sends a final null in the Server attribute, so
+ * only error if the null appears anywhere else in a string */
+ if (strlen(result) != attrlen-1) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Error in string: %zd/%d", strlen(result), attrlen);
+ ABORT(R_FAILED);
+ }
+ }
+
+ _status = 0;
+ abort:
+ return _status;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_string = {
+ "string",
+ nr_stun_attr_codec_string_print,
+ nr_stun_attr_codec_string_encode,
+ nr_stun_attr_codec_string_decode
+};
+
+static int
+nr_stun_attr_codec_unknown_attributes_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ nr_stun_attr_unknown_attributes *unknown_attributes = data;
+ char type[9];
+ char str[64 + (NR_STUN_MAX_UNKNOWN_ATTRIBUTES * sizeof(type))];
+ int i;
+
+ snprintf(str, sizeof(str), "%s %s:", msg, attr_info->name);
+ for (i = 0; i < unknown_attributes->num_attributes; ++i) {
+ snprintf(type, sizeof(type), "%s 0x%04x", ((i>0)?",":""), unknown_attributes->attribute[i]);
+ strlcat(str, type, sizeof(str));
+ }
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s", str);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_unknown_attributes_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ int _status;
+ int start = offset;
+ nr_stun_attr_unknown_attributes *unknown_attributes = data;
+ int length = (2 * unknown_attributes->num_attributes);
+ int i;
+
+ if (unknown_attributes->num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Too many UNKNOWN-ATTRIBUTES: %d", unknown_attributes->num_attributes);
+ ABORT(R_FAILED);
+ }
+
+ if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
+ || nr_stun_encode_htons(length , buflen, buf, &offset))
+ ABORT(R_FAILED);
+
+ for (i = 0; i < unknown_attributes->num_attributes; ++i) {
+ if (nr_stun_encode_htons(unknown_attributes->attribute[i], buflen, buf, &offset))
+ ABORT(R_FAILED);
+ }
+
+ *attrlen = offset - start;
+
+ _status = 0;
+ abort:
+ return _status;
+}
+
+static int
+nr_stun_attr_codec_unknown_attributes_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ int _status;
+ nr_stun_attr_unknown_attributes *unknown_attributes = data;
+ int i;
+ UINT2 *a;
+
+ if ((attrlen % 4) != 0) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Attribute is illegal size: %d", attrlen);
+ ABORT(R_REJECTED);
+ }
+
+ unknown_attributes->num_attributes = attrlen / 2;
+
+ if (unknown_attributes->num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Too many UNKNOWN-ATTRIBUTES: %d", unknown_attributes->num_attributes);
+ ABORT(R_REJECTED);
+ }
+
+ for (i = 0; i < unknown_attributes->num_attributes; ++i) {
+ a = &(unknown_attributes->attribute[i]);
+ if (nr_stun_decode_htons(buf, buflen, &offset, a))
+ return R_FAILED;
+ }
+
+ _status = 0;
+ abort:
+ return _status;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_unknown_attributes = {
+ "unknown_attributes",
+ nr_stun_attr_codec_unknown_attributes_print,
+ nr_stun_attr_codec_unknown_attributes_encode,
+ nr_stun_attr_codec_unknown_attributes_decode
+};
+
+static int
+nr_stun_attr_codec_xor_mapped_address_print(nr_stun_attr_info *attr_info, char *msg, void *data)
+{
+ nr_stun_attr_xor_mapped_address *xor_mapped_address = data;
+ r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s (unmasked) %s (masked)",
+ msg, attr_info->name,
+ xor_mapped_address->unmasked.as_string,
+ xor_mapped_address->masked.as_string);
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_xor_mapped_address_encode(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen)
+{
+ nr_stun_attr_xor_mapped_address *xor_mapped_address = data;
+ nr_stun_message_header *header = (nr_stun_message_header*)buf;
+ UINT4 magic_cookie;
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
+
+ /* this needs to be the magic cookie in the header and not
+ * the MAGIC_COOKIE constant because if we're talking to
+ * older servers (that don't have a magic cookie) they use
+ * message ID for this */
+ magic_cookie = ntohl(header->magic_cookie);
+
+ nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
+
+ if (nr_stun_attr_codec_addr.encode(attr_info, &xor_mapped_address->masked, offset, buflen, buf, attrlen))
+ return R_FAILED;
+
+ return 0;
+}
+
+static int
+nr_stun_attr_codec_xor_mapped_address_decode(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data)
+{
+ int r,_status;
+ nr_stun_attr_xor_mapped_address *xor_mapped_address = data;
+ nr_stun_message_header *header = (nr_stun_message_header*)buf;
+ UINT4 magic_cookie;
+
+ if ((r=nr_stun_attr_codec_addr.decode(attr_info, attrlen, buf, offset, buflen, &xor_mapped_address->masked)))
+ ABORT(r);
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
+
+ /* this needs to be the magic cookie in the header and not
+ * the MAGIC_COOKIE constant because if we're talking to
+ * older servers (that don't have a magic cookie) they use
+ * message ID for this */
+ magic_cookie = ntohl(header->magic_cookie);
+
+ nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
+
+ _status = 0;
+ abort:
+ return _status;
+}
+
+nr_stun_attr_codec nr_stun_attr_codec_xor_mapped_address = {
+ "xor_mapped_address",
+ nr_stun_attr_codec_xor_mapped_address_print,
+ nr_stun_attr_codec_xor_mapped_address_encode,
+ nr_stun_attr_codec_xor_mapped_address_decode
+};
+
+nr_stun_attr_codec nr_stun_attr_codec_old_xor_mapped_address = {
+ "xor_mapped_address",
+ nr_stun_attr_codec_xor_mapped_address_print,
+ 0, /* never encode this type */
+ nr_stun_attr_codec_xor_mapped_address_decode
+};
+
+nr_stun_attr_codec nr_stun_attr_codec_xor_peer_address = {
+ "xor_peer_address",
+ nr_stun_attr_codec_xor_mapped_address_print,
+ nr_stun_attr_codec_xor_mapped_address_encode,
+ nr_stun_attr_codec_xor_mapped_address_decode
+};
+
+#define NR_ADD_STUN_ATTRIBUTE(type, name, codec, illegal) \
+ { (type), (name), &(codec), illegal },
+
+#define NR_ADD_STUN_ATTRIBUTE_IGNORE(type, name) \
+ { (type), (name), &nr_stun_attr_codec_noop, 0 },
+
+
+static nr_stun_attr_info attrs[] = {
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ALTERNATE_SERVER, "ALTERNATE-SERVER", nr_stun_attr_codec_addr, 0)
+#ifdef USE_STUND_0_96
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_OLD_CHANGE_REQUEST, "CHANGE-REQUEST", nr_stun_attr_codec_UINT4, 0)
+#endif
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ERROR_CODE, "ERROR-CODE", nr_stun_attr_codec_error_code, nr_stun_attr_error_code_illegal)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_FINGERPRINT, "FINGERPRINT", nr_stun_attr_codec_fingerprint, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_MAPPED_ADDRESS, "MAPPED-ADDRESS", nr_stun_attr_codec_addr, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_MESSAGE_INTEGRITY, "MESSAGE-INTEGRITY", nr_stun_attr_codec_message_integrity, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_NONCE, "NONCE", nr_stun_attr_codec_quoted_string, nr_stun_attr_nonce_illegal)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_REALM, "REALM", nr_stun_attr_codec_quoted_string, nr_stun_attr_realm_illegal)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_SERVER, "SERVER", nr_stun_attr_codec_string, nr_stun_attr_server_illegal)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_UNKNOWN_ATTRIBUTES, "UNKNOWN-ATTRIBUTES", nr_stun_attr_codec_unknown_attributes, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_USERNAME, "USERNAME", nr_stun_attr_codec_string, nr_stun_attr_username_illegal)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_MAPPED_ADDRESS, "XOR-MAPPED-ADDRESS", nr_stun_attr_codec_xor_mapped_address, 0)
+
+#ifdef USE_ICE
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ICE_CONTROLLED, "ICE-CONTROLLED", nr_stun_attr_codec_UINT8, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ICE_CONTROLLING, "ICE-CONTROLLING", nr_stun_attr_codec_UINT8, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_PRIORITY, "PRIORITY", nr_stun_attr_codec_UINT4, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_USE_CANDIDATE, "USE-CANDIDATE", nr_stun_attr_codec_flag, 0)
+#endif
+
+#ifdef USE_TURN
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_DATA, "DATA", nr_stun_attr_codec_data, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_LIFETIME, "LIFETIME", nr_stun_attr_codec_UINT4, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_RELAY_ADDRESS, "XOR-RELAY-ADDRESS", nr_stun_attr_codec_xor_mapped_address, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_PEER_ADDRESS, "XOR-PEER-ADDRESS", nr_stun_attr_codec_xor_peer_address, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_REQUESTED_TRANSPORT, "REQUESTED-TRANSPORT", nr_stun_attr_codec_UCHAR, 0)
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_BANDWIDTH, "BANDWIDTH", nr_stun_attr_codec_UINT4, 0)
+#endif /* USE_TURN */
+
+ /* for backwards compatibilty */
+ NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_OLD_XOR_MAPPED_ADDRESS, "Old XOR-MAPPED-ADDRESS", nr_stun_attr_codec_old_xor_mapped_address, 0)
+#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
+ NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_RESPONSE_ADDRESS, "RESPONSE-ADDRESS")
+ NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_SOURCE_ADDRESS, "SOURCE-ADDRESS")
+ NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_CHANGED_ADDRESS, "CHANGED-ADDRESS")
+ NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_PASSWORD, "PASSWORD")
+#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
+};
+
+
+int
+nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info)
+{
+ int _status;
+ size_t i;
+
+ *info = 0;
+ for (i = 0; i < sizeof(attrs)/sizeof(*attrs); ++i) {
+ if (type == attrs[i].type) {
+ *info = &attrs[i];
+ break;
+ }
+ }
+
+ if (*info == 0)
+ ABORT(R_NOT_FOUND);
+
+ _status=0;
+ abort:
+ return(_status);
+}
+
+int
+nr_stun_fix_attribute_ordering(nr_stun_message *msg)
+{
+ nr_stun_message_attribute *message_integrity;
+ nr_stun_message_attribute *fingerprint;
+
+ /* 2nd to the last */
+ if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_MESSAGE_INTEGRITY, &message_integrity)) {
+ TAILQ_REMOVE(&msg->attributes, message_integrity, entry);
+ TAILQ_INSERT_TAIL(&msg->attributes, message_integrity, entry);
+ }
+
+ /* last */
+ if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT, &fingerprint)) {
+ TAILQ_REMOVE(&msg->attributes, fingerprint, entry);
+ TAILQ_INSERT_TAIL(&msg->attributes, fingerprint, entry);
+ }
+
+ return 0;
+}
+
+// Since this sanity check is only a collection of assert statements and those
+// assert statements are compiled out in non-debug builds, undef SANITY_CHECKS
+// so we can avoid the warning that padding_bytes is never used in opt builds.
+#ifdef NDEBUG
+#undef SANITY_CHECKS
+#endif
+
+#ifdef SANITY_CHECKS
+static void sanity_check_encoding_stuff(nr_stun_message *msg)
+{
+ nr_stun_message_attribute *attr = 0;
+ int padding_bytes;
+ int l;
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Starting to sanity check encoding");
+
+ l = 0;
+ TAILQ_FOREACH(attr, &msg->attributes, entry) {
+ padding_bytes = 0;
+ if ((attr->length % 4) != 0) {
+ padding_bytes = 4 - (attr->length % 4);
+ }
+ assert(attr->length == (attr->encoding_length - (4 + padding_bytes)));
+ assert(((void*)attr->encoding) == (msg->buffer + 20 + l));
+ l += attr->encoding_length;
+ assert((l % 4) == 0);
+ }
+ assert(l == msg->header.length);
+}
+#endif /* SANITY_CHECKS */
+
+
+int
+nr_stun_encode_message(nr_stun_message *msg)
+{
+ int r,_status;
+ size_t length_offset;
+ size_t length_offset_hold;
+ nr_stun_attr_info *attr_info;
+ nr_stun_message_attribute *attr;
+ int padding_bytes;
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Encoding STUN message");
+
+ nr_stun_fix_attribute_ordering(msg);
+
+ msg->name = nr_stun_msg_type(msg->header.type);
+ msg->length = 0;
+ msg->header.length = 0;
+
+ if ((r=nr_stun_encode_htons(msg->header.type, sizeof(msg->buffer), msg->buffer, &msg->length)))
+ ABORT(r);
+ if (msg->name)
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded MsgType: %s", msg->name);
+ else
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded MsgType: 0x%03x", msg->header.type);
+
+ /* grab the offset to be used later to re-write the header length field */
+ length_offset_hold = msg->length;
+
+ if ((r=nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &msg->length)))
+ ABORT(r);
+
+ if ((r=nr_stun_encode_htonl(msg->header.magic_cookie, sizeof(msg->buffer), msg->buffer, &msg->length)))
+ ABORT(r);
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded Cookie: %08x", msg->header.magic_cookie);
+
+ if ((r=nr_stun_encode((UCHAR*)(&msg->header.id), sizeof(msg->header.id), sizeof(msg->buffer), msg->buffer, &msg->length)))
+ ABORT(r);
+ r_dump(NR_LOG_STUN, LOG_DEBUG, "Encoded ID", (void*)&msg->header.id, sizeof(msg->header.id));
+
+ TAILQ_FOREACH(attr, &msg->attributes, entry) {
+ if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Unrecognized attribute: 0x%04x", attr->type);
+ ABORT(R_INTERNAL);
+ }
+
+ attr->name = attr_info->name;
+ attr->type_name = attr_info->codec->name;
+ attr->encoding = (nr_stun_encoded_attribute*)&msg->buffer[msg->length];
+
+ if (attr_info->codec->encode != 0) {
+ if ((r=attr_info->codec->encode(attr_info, &attr->u, msg->length, sizeof(msg->buffer), msg->buffer, &attr->encoding_length))) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Unable to encode %s", attr_info->name);
+ ABORT(r);
+ }
+
+ msg->length += attr->encoding_length;
+ attr->length = attr->encoding_length - 4; /* -4 for type and length fields */
+
+ if (attr_info->illegal) {
+ if ((r=attr_info->illegal(attr_info, attr->length, &attr->u)))
+ ABORT(r);
+ }
+
+ attr_info->codec->print(attr_info, "Encoded", &attr->u);
+
+ if ((attr->length % 4) == 0) {
+ padding_bytes = 0;
+ }
+ else {
+ padding_bytes = 4 - (attr->length % 4);
+ nr_stun_encode((UCHAR*)"\0\0\0\0", padding_bytes, sizeof(msg->buffer), msg->buffer, &msg->length);
+ attr->encoding_length += padding_bytes;
+ }
+
+ msg->header.length += attr->encoding_length;
+ length_offset = length_offset_hold;
+ (void)nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &length_offset);
+ }
+ else {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Missing encode function for attribute: %s", attr_info->name);
+ }
+ }
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded Length: %d", msg->header.length);
+
+ assert(msg->length < NR_STUN_MAX_MESSAGE_SIZE);
+
+#ifdef SANITY_CHECKS
+ sanity_check_encoding_stuff(msg);
+#endif /* SANITY_CHECKS */
+
+ _status=0;
+abort:
+ return _status;
+}
+
+int
+nr_stun_decode_message(nr_stun_message *msg, int (*get_password)(void *arg, nr_stun_message *msg, Data **password), void *arg)
+{
+ int r,_status;
+ int offset;
+ int size;
+ int padding_bytes;
+ nr_stun_message_attribute *attr;
+ nr_stun_attr_info *attr_info;
+ Data *password;
+
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Parsing STUN message of %d bytes", msg->length);
+
+ if (!TAILQ_EMPTY(&msg->attributes))
+ ABORT(R_BAD_ARGS);
+
+ if (sizeof(nr_stun_message_header) > msg->length) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Message too small");
+ ABORT(R_FAILED);
+ }
+
+ memcpy(&msg->header, msg->buffer, sizeof(msg->header));
+ msg->header.type = ntohs(msg->header.type);
+ msg->header.length = ntohs(msg->header.length);
+ msg->header.magic_cookie = ntohl(msg->header.magic_cookie);
+
+ msg->name = nr_stun_msg_type(msg->header.type);
+
+ if (msg->name)
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed MsgType: %s", msg->name);
+ else
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed MsgType: 0x%03x", msg->header.type);
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed Length: %d", msg->header.length);
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed Cookie: %08x", msg->header.magic_cookie);
+ r_dump(NR_LOG_STUN, LOG_DEBUG, "Parsed ID", (void*)&msg->header.id, sizeof(msg->header.id));
+
+ if (msg->header.length + sizeof(msg->header) != msg->length) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Inconsistent message header length: %d/%d",
+ msg->header.length, msg->length);
+ ABORT(R_FAILED);
+ }
+
+ size = msg->header.length;
+
+ if ((size % 4) != 0) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Illegal message size: %d", msg->header.length);
+ ABORT(R_FAILED);
+ }
+
+ offset = sizeof(msg->header);
+
+ while (size > 0) {
+ r_log(NR_LOG_STUN, LOG_DEBUG, "size = %d", size);
+
+ if (size < 4) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Illegal message length: %d", size);
+ ABORT(R_FAILED);
+ }
+
+ if ((r=nr_stun_message_attribute_create(msg, &attr)))
+ ABORT(R_NO_MEMORY);
+
+ attr->encoding = (nr_stun_encoded_attribute*)&msg->buffer[offset];
+ attr->type = ntohs(attr->encoding->type);
+ attr->length = ntohs(attr->encoding->length);
+ attr->encoding_length = attr->length + 4;
+
+ if ((attr->length % 4) != 0) {
+ padding_bytes = 4 - (attr->length % 4);
+ attr->encoding_length += padding_bytes;
+ }
+
+ if ((attr->encoding_length) > (size_t)size) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Attribute length larger than remaining message size: %d/%d", attr->encoding_length, size);
+ ABORT(R_FAILED);
+ }
+
+ if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) {
+ if (attr->type <= 0x7FFF)
+ ++msg->comprehension_required_unknown_attributes;
+ else
+ ++msg->comprehension_optional_unknown_attributes;
+ r_log(NR_LOG_STUN, LOG_INFO, "Unrecognized attribute: 0x%04x", attr->type);
+ }
+ else {
+ attr_info->name = attr_info->name;
+ attr->type_name = attr_info->codec->name;
+
+ if (attr->type == NR_STUN_ATTR_MESSAGE_INTEGRITY) {
+ if (get_password && get_password(arg, msg, &password) == 0) {
+ if (password->len > sizeof(attr->u.message_integrity.password)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Password too long: %d bytes", password->len);
+ ABORT(R_FAILED);
+ }
+
+ memcpy(attr->u.message_integrity.password, password->data, password->len);
+ attr->u.message_integrity.passwordlen = password->len;
+ }
+ else {
+ /* set to user "not found" */
+ attr->u.message_integrity.unknown_user = 1;
+ }
+ }
+ else if (attr->type == NR_STUN_ATTR_OLD_XOR_MAPPED_ADDRESS) {
+ attr->type = NR_STUN_ATTR_XOR_MAPPED_ADDRESS;
+ r_log(NR_LOG_STUN, LOG_INFO, "Translating obsolete XOR-MAPPED-ADDRESS type");
+ }
+
+ if ((r=attr_info->codec->decode(attr_info, attr->length, msg->buffer, offset+4, msg->length, &attr->u))) {
+ if (r == SKIP_ATTRIBUTE_DECODE) {
+ r_log(NR_LOG_STUN, LOG_INFO, "Skipping %s", attr_info->name);
+ }
+ else {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Unable to parse %s", attr_info->name);
+ }
+
+ attr->invalid = 1;
+ }
+ else {
+ attr_info->codec->print(attr_info, "Parsed", &attr->u);
+
+#ifdef USE_STUN_PEDANTIC
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Before pedantic attr_info checks");
+ if (attr_info->illegal) {
+ if ((r=attr_info->illegal(attr_info, attr->length, &attr->u))) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Failed pedantic attr_info checks");
+ ABORT(r);
+ }
+ }
+ r_log(NR_LOG_STUN, LOG_DEBUG, "After pedantic attr_info checks");
+#endif /* USE_STUN_PEDANTIC */
+ }
+ }
+
+ offset += attr->encoding_length;
+ size -= attr->encoding_length;
+ }
+
+#ifdef SANITY_CHECKS
+ sanity_check_encoding_stuff(msg);
+#endif /* SANITY_CHECKS */
+
+ _status=0;
+ abort:
+ return _status;
+}
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.h
new file mode 100644
index 0000000000..4e4ff60e0c
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_codec.h
@@ -0,0 +1,78 @@
+/*
+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_codec_h
+#define _stun_codec_h
+
+#include "stun_msg.h"
+
+typedef struct nr_stun_attr_info_ nr_stun_attr_info;
+
+typedef struct nr_stun_attr_codec_ {
+ char *name;
+ int (*print)(nr_stun_attr_info *attr_info, char *msg, void *data);
+ int (*encode)(nr_stun_attr_info *attr_info, void *data, size_t offset, size_t buflen, UCHAR *buf, size_t *attrlen);
+ int (*decode)(nr_stun_attr_info *attr_info, size_t attrlen, UCHAR *buf, size_t offset, size_t buflen, void *data);
+} nr_stun_attr_codec;
+
+struct nr_stun_attr_info_ {
+ UINT2 type;
+ char *name;
+ nr_stun_attr_codec *codec;
+ int (*illegal)(nr_stun_attr_info *attr_info, size_t attrlen, void *data);
+};
+
+extern nr_stun_attr_codec nr_stun_attr_codec_UINT4;
+extern nr_stun_attr_codec nr_stun_attr_codec_UINT8;
+extern nr_stun_attr_codec nr_stun_attr_codec_addr;
+extern nr_stun_attr_codec nr_stun_attr_codec_bytes;
+extern nr_stun_attr_codec nr_stun_attr_codec_data;
+extern nr_stun_attr_codec nr_stun_attr_codec_error_code;
+extern nr_stun_attr_codec nr_stun_attr_codec_fingerprint;
+extern nr_stun_attr_codec nr_stun_attr_codec_flag;
+extern nr_stun_attr_codec nr_stun_attr_codec_message_integrity;
+extern nr_stun_attr_codec nr_stun_attr_codec_noop;
+extern nr_stun_attr_codec nr_stun_attr_codec_quoted_string;
+extern nr_stun_attr_codec nr_stun_attr_codec_string;
+extern nr_stun_attr_codec nr_stun_attr_codec_unknown_attributes;
+extern nr_stun_attr_codec nr_stun_attr_codec_xor_mapped_address;
+extern nr_stun_attr_codec nr_stun_attr_codec_xor_peer_address;
+extern nr_stun_attr_codec nr_stun_attr_codec_old_xor_mapped_address;
+
+size_t nr_count_utf8_code_points_without_validation(const char *s);
+int nr_stun_encode_message(nr_stun_message *msg);
+int nr_stun_decode_message(nr_stun_message *msg, int (*get_password)(void *arg, nr_stun_message *msg, Data **password), void *arg);
+
+#endif
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_hint.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_hint.c
new file mode 100644
index 0000000000..8f118e8942
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_hint.c
@@ -0,0 +1,245 @@
+/*
+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.
+*/
+
+#include <errno.h>
+#include <csi_platform.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <stdlib.h>
+#include <io.h>
+#include <time.h>
+#else /* UNIX */
+#include <string.h>
+#endif /* end UNIX */
+#include <assert.h>
+
+#include "stun.h"
+
+
+/* returns 0 if it's not a STUN message
+ * 1 if it's likely to be a STUN message
+ * 2 if it's super likely to be a STUN message
+ * 3 if it really is a STUN message */
+int
+nr_is_stun_message(UCHAR *buf, size_t len)
+{
+ const UINT4 cookie = htonl(NR_STUN_MAGIC_COOKIE);
+ const UINT4 cookie2 = htonl(NR_STUN_MAGIC_COOKIE2);
+#if 0
+ nr_stun_message msg;
+#endif
+ UINT2 type;
+ nr_stun_encoded_attribute* attr;
+ unsigned int attrLen;
+ int atrType;
+
+ if (sizeof(nr_stun_message_header) > len)
+ return 0;
+
+ if ((buf[0] & (0x80|0x40)) != 0)
+ return 0;
+
+ memcpy(&type, buf, 2);
+ type = ntohs(type);
+
+ switch (type) {
+ case NR_STUN_MSG_BINDING_REQUEST:
+ case NR_STUN_MSG_BINDING_INDICATION:
+ case NR_STUN_MSG_BINDING_RESPONSE:
+ case NR_STUN_MSG_BINDING_ERROR_RESPONSE:
+
+#ifdef USE_TURN
+ case NR_STUN_MSG_ALLOCATE_REQUEST:
+ case NR_STUN_MSG_ALLOCATE_RESPONSE:
+ case NR_STUN_MSG_ALLOCATE_ERROR_RESPONSE:
+ case NR_STUN_MSG_REFRESH_REQUEST:
+ case NR_STUN_MSG_REFRESH_RESPONSE:
+ case NR_STUN_MSG_REFRESH_ERROR_RESPONSE:
+ case NR_STUN_MSG_PERMISSION_REQUEST:
+ case NR_STUN_MSG_PERMISSION_RESPONSE:
+ case NR_STUN_MSG_PERMISSION_ERROR_RESPONSE:
+ case NR_STUN_MSG_CHANNEL_BIND_REQUEST:
+ case NR_STUN_MSG_CHANNEL_BIND_RESPONSE:
+ case NR_STUN_MSG_CHANNEL_BIND_ERROR_RESPONSE:
+ case NR_STUN_MSG_SEND_INDICATION:
+ case NR_STUN_MSG_DATA_INDICATION:
+#ifdef NR_STUN_MSG_CONNECT_REQUEST
+ case NR_STUN_MSG_CONNECT_REQUEST:
+#endif
+#ifdef NR_STUN_MSG_CONNECT_RESPONSE
+ case NR_STUN_MSG_CONNECT_RESPONSE:
+#endif
+#ifdef NR_STUN_MSG_CONNECT_ERROR_RESPONSE
+ case NR_STUN_MSG_CONNECT_ERROR_RESPONSE:
+#endif
+#ifdef NR_STUN_MSG_CONNECT_STATUS_INDICATION
+ case NR_STUN_MSG_CONNECT_STATUS_INDICATION:
+#endif
+#endif /* USE_TURN */
+
+ /* ok so far, continue */
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ if (!memcmp(&cookie2, &buf[4], sizeof(UINT4))) {
+ /* return here because if it's an old-style message then there will
+ * not be a fingerprint in the message */
+ return 1;
+ }
+
+ if (memcmp(&cookie, &buf[4], sizeof(UINT4)))
+ return 0;
+
+ /* the magic cookie was right, so it's pretty darn likely that what we've
+ * got here is a STUN message */
+
+ attr = (nr_stun_encoded_attribute*)(buf + (len - 8));
+ attrLen = ntohs(attr->length);
+ atrType = ntohs(attr->type);
+
+ if (atrType != NR_STUN_ATTR_FINGERPRINT || attrLen != 4)
+ return 1;
+
+ /* the fingerprint is in the right place and looks sane, so we can be quite
+ * sure we've got a STUN message */
+
+#if 0
+/* nevermind this check ... there's a reasonable chance that a NAT has modified
+ * the message (and thus the fingerprint check will fail), but it's still an
+ * otherwise-perfectly-good STUN message, so skip the check since we're going
+ * to return "true" whether the check succeeds or fails */
+
+ if (nr_stun_parse_attr_UINT4(buf + (len - 4), attrLen, &msg.fingerprint))
+ return 2;
+
+
+ if (nr_stun_compute_fingerprint(buf, len - 8, &computedFingerprint))
+ return 2;
+
+ if (msg.fingerprint.number != computedFingerprint)
+ return 2;
+
+ /* and the fingerprint is good, so it's gotta be a STUN message */
+#endif
+
+ return 3;
+}
+
+int
+nr_is_stun_request_message(UCHAR *buf, size_t len)
+{
+ UINT2 type;
+
+ if (sizeof(nr_stun_message_header) > len)
+ return 0;
+
+ if (!nr_is_stun_message(buf, len))
+ return 0;
+
+ memcpy(&type, buf, 2);
+ type = ntohs(type);
+
+ return NR_STUN_GET_TYPE_CLASS(type) == NR_CLASS_REQUEST;
+}
+
+int
+nr_is_stun_indication_message(UCHAR *buf, size_t len)
+{
+ UINT2 type;
+
+ if (sizeof(nr_stun_message_header) > len)
+ return 0;
+
+ if (!nr_is_stun_message(buf, len))
+ return 0;
+
+ memcpy(&type, buf, 2);
+ type = ntohs(type);
+
+ return NR_STUN_GET_TYPE_CLASS(type) == NR_CLASS_INDICATION;
+}
+
+int
+nr_is_stun_response_message(UCHAR *buf, size_t len)
+{
+ UINT2 type;
+
+ if (sizeof(nr_stun_message_header) > len)
+ return 0;
+
+ if (!nr_is_stun_message(buf, len))
+ return 0;
+
+ memcpy(&type, buf, 2);
+ type = ntohs(type);
+
+ return NR_STUN_GET_TYPE_CLASS(type) == NR_CLASS_RESPONSE
+ || NR_STUN_GET_TYPE_CLASS(type) == NR_CLASS_ERROR_RESPONSE;
+}
+
+int
+nr_has_stun_cookie(UCHAR *buf, size_t len)
+{
+ static UINT4 cookie;
+
+ cookie = htonl(NR_STUN_MAGIC_COOKIE);
+
+ if (sizeof(nr_stun_message_header) > len)
+ return 0;
+
+ if (memcmp(&cookie, &buf[4], sizeof(UINT4)))
+ return 0;
+
+ return 1;
+}
+
+int
+nr_stun_message_length(UCHAR *buf, int buf_len, int *msg_len)
+{
+ nr_stun_message_header *hdr;
+
+ if (!nr_is_stun_message(buf, buf_len))
+ return(R_BAD_DATA);
+
+ hdr = (nr_stun_message_header *)buf;
+
+ *msg_len = ntohs(hdr->length);
+
+ return(0);
+}
+
+
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_hint.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_hint.h
new file mode 100644
index 0000000000..c2badc1d2b
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_hint.h
@@ -0,0 +1,44 @@
+/*
+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_hint_h
+#define _stun_hint_h
+
+int nr_is_stun_message(UCHAR *buf, size_t len);
+int nr_is_stun_request_message(UCHAR *buf, size_t len);
+int nr_is_stun_response_message(UCHAR *buf, size_t len);
+int nr_is_stun_indication_message(UCHAR *buf, size_t len);
+int nr_has_stun_cookie(UCHAR *buf, size_t len);
+int nr_stun_message_length(UCHAR *buf, int len, int *length);
+
+#endif
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_msg.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_msg.c
new file mode 100644
index 0000000000..7e01686109
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_msg.c
@@ -0,0 +1,364 @@
+/*
+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.
+*/
+
+#include <errno.h>
+#include <csi_platform.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <stdlib.h>
+#include <io.h>
+#include <time.h>
+#else /* UNIX */
+#include <string.h>
+#endif /* end UNIX */
+#include <assert.h>
+
+#include "stun.h"
+
+
+int
+nr_stun_message_create(nr_stun_message **msg)
+{
+ int _status;
+ nr_stun_message *m = 0;
+
+ m = RCALLOC(sizeof(*m));
+ if (!m)
+ ABORT(R_NO_MEMORY);
+
+ TAILQ_INIT(&m->attributes);
+
+ *msg = m;
+
+ _status=0;
+ abort:
+ return(_status);
+}
+
+int
+nr_stun_message_create2(nr_stun_message **msg, UCHAR *buffer, size_t length)
+{
+ int r,_status;
+ nr_stun_message *m = 0;
+
+ if (length > sizeof(m->buffer)) {
+ ABORT(R_BAD_DATA);
+ }
+
+ if ((r=nr_stun_message_create(&m)))
+ ABORT(r);
+
+ memcpy(m->buffer, buffer, length);
+ m->length = length;
+
+ *msg = m;
+
+ _status=0;
+ abort:
+ return(_status);
+}
+
+int
+nr_stun_message_destroy(nr_stun_message **msg)
+{
+ int _status;
+ nr_stun_message_attribute_head *attrs;
+ nr_stun_message_attribute *attr;
+
+ if (msg && *msg) {
+ attrs = &(*msg)->attributes;
+ while (!TAILQ_EMPTY(attrs)) {
+ attr = TAILQ_FIRST(attrs);
+ nr_stun_message_attribute_destroy(*msg, &attr);
+ }
+
+ RFREE(*msg);
+
+ *msg = 0;
+ }
+
+ _status=0;
+/* abort: */
+ return(_status);
+}
+
+int
+nr_stun_message_attribute_create(nr_stun_message *msg, nr_stun_message_attribute **attr)
+{
+ int _status;
+ nr_stun_message_attribute *a = 0;
+
+ a = RCALLOC(sizeof(*a));
+ if (!a)
+ ABORT(R_NO_MEMORY);
+
+ TAILQ_INSERT_TAIL(&msg->attributes, a, entry);
+
+ *attr = a;
+
+ _status=0;
+ abort:
+ return(_status);
+}
+
+int
+nr_stun_message_attribute_destroy(nr_stun_message *msg, nr_stun_message_attribute **attr)
+{
+ int _status;
+ nr_stun_message_attribute *a = 0;
+
+ if (attr && *attr) {
+ a = *attr;
+ TAILQ_REMOVE(&msg->attributes, a, entry);
+
+ RFREE(a);
+
+ *attr = 0;
+ }
+
+ _status=0;
+/* abort: */
+ return(_status);
+}
+
+int
+nr_stun_message_has_attribute(nr_stun_message *msg, UINT2 type, nr_stun_message_attribute **attribute)
+{
+ nr_stun_message_attribute *attr = 0;
+ nr_stun_message_get_attribute(msg, type, 0, &attr);
+
+ if (attribute)
+ *attribute = attr;
+
+ return attr ? 1 : 0;
+}
+
+int
+nr_stun_message_get_attribute(nr_stun_message *msg, UINT2 type, UINT2 index, nr_stun_message_attribute **attribute)
+{
+ nr_stun_message_attribute *attr;
+ TAILQ_FOREACH(attr, &msg->attributes, entry) {
+ if (attr->type == type && !attr->invalid) {
+ if (!index) {
+ *attribute = attr;
+ return 0;
+ }
+ --index;
+ }
+ }
+ *attribute = 0;
+ return R_NOT_FOUND;
+}
+
+#define NR_STUN_MESSAGE_ADD_ATTRIBUTE(__type, __code) \
+ { \
+ int r,_status; \
+ nr_stun_message_attribute *attr = 0; \
+ if ((r=nr_stun_message_attribute_create(msg, &attr))) \
+ ABORT(r); \
+ attr->type = (__type); \
+ { __code } \
+ _status=0; \
+ abort: \
+ if (_status){ \
+ nr_stun_message_attribute_destroy(msg, &attr); \
+ } \
+ return(_status); \
+ }
+
+
+int
+nr_stun_message_add_alternate_server_attribute(nr_stun_message *msg, nr_transport_addr *alternate_server)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_ALTERNATE_SERVER,
+ {
+ if ((r=nr_transport_addr_copy(&attr->u.alternate_server, alternate_server)))
+ ABORT(r);
+ }
+)
+
+int
+nr_stun_message_add_error_code_attribute(nr_stun_message *msg, UINT2 number, char *reason)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_ERROR_CODE,
+ {
+ attr->u.error_code.number = number;
+ (void)strlcpy(attr->u.error_code.reason, reason, sizeof(attr->u.error_code.reason));
+ }
+)
+
+int
+nr_stun_message_add_fingerprint_attribute(nr_stun_message *msg)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_FINGERPRINT,
+ {}
+)
+
+int
+nr_stun_message_add_message_integrity_attribute(nr_stun_message *msg, Data *password)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_MESSAGE_INTEGRITY,
+ {
+ if (sizeof(attr->u.message_integrity.password) < password->len)
+ ABORT(R_BAD_DATA);
+
+ memcpy(attr->u.message_integrity.password, password->data, password->len);
+ attr->u.message_integrity.passwordlen = password->len;
+ }
+)
+
+int
+nr_stun_message_add_nonce_attribute(nr_stun_message *msg, char *nonce)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_NONCE,
+ { (void)strlcpy(attr->u.nonce, nonce, sizeof(attr->u.nonce)); }
+)
+
+int
+nr_stun_message_add_realm_attribute(nr_stun_message *msg, char *realm)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_REALM,
+ { (void)strlcpy(attr->u.realm, realm, sizeof(attr->u.realm)); }
+)
+
+int
+nr_stun_message_add_server_attribute(nr_stun_message *msg, char *server_name)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_SERVER,
+ { (void)strlcpy(attr->u.server_name, server_name, sizeof(attr->u.server_name)); }
+)
+
+int
+nr_stun_message_add_unknown_attributes_attribute(nr_stun_message *msg, nr_stun_attr_unknown_attributes *unknown_attributes)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_UNKNOWN_ATTRIBUTES,
+ { memcpy(&attr->u.unknown_attributes, unknown_attributes, sizeof(attr->u.unknown_attributes)); }
+)
+
+int
+nr_stun_message_add_username_attribute(nr_stun_message *msg, char *username)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_USERNAME,
+ { (void)strlcpy(attr->u.username, username, sizeof(attr->u.username)); }
+)
+
+int
+nr_stun_message_add_requested_transport_attribute(nr_stun_message *msg, UCHAR protocol)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_REQUESTED_TRANSPORT,
+ { attr->u.requested_transport = protocol; }
+)
+
+int
+nr_stun_message_add_xor_mapped_address_attribute(nr_stun_message *msg, nr_transport_addr *mapped_address)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_XOR_MAPPED_ADDRESS,
+ {
+ if ((r=nr_transport_addr_copy(&attr->u.xor_mapped_address.unmasked, mapped_address)))
+ ABORT(r);
+ }
+)
+
+int
+nr_stun_message_add_xor_peer_address_attribute(nr_stun_message *msg, nr_transport_addr *peer_address)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_XOR_PEER_ADDRESS,
+ {
+ if ((r=nr_transport_addr_copy(&attr->u.xor_mapped_address.unmasked, peer_address)))
+ ABORT(r);
+ }
+)
+
+#ifdef USE_ICE
+int
+nr_stun_message_add_ice_controlled_attribute(nr_stun_message *msg, UINT8 ice_controlled)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_ICE_CONTROLLED,
+ { attr->u.ice_controlled = ice_controlled; }
+)
+
+int
+nr_stun_message_add_ice_controlling_attribute(nr_stun_message *msg, UINT8 ice_controlling)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_ICE_CONTROLLING,
+ { attr->u.ice_controlling = ice_controlling; }
+)
+
+int
+nr_stun_message_add_priority_attribute(nr_stun_message *msg, UINT4 priority)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_PRIORITY,
+ { attr->u.priority = priority; }
+)
+
+int
+nr_stun_message_add_use_candidate_attribute(nr_stun_message *msg)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_USE_CANDIDATE,
+ {}
+)
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+int
+nr_stun_message_add_data_attribute(nr_stun_message *msg, UCHAR *data, int length)
+
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_DATA,
+ {
+ if (length > NR_STUN_MAX_MESSAGE_SIZE)
+ ABORT(R_BAD_ARGS);
+
+ memcpy(attr->u.data.data, data, length);
+ attr->u.data.length=length;
+ }
+)
+
+int
+nr_stun_message_add_lifetime_attribute(nr_stun_message *msg, UINT4 lifetime_secs)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_LIFETIME,
+ { attr->u.lifetime_secs = lifetime_secs; }
+)
+
+#endif /* USE_TURN */
+
+#ifdef USE_STUND_0_96
+int
+nr_stun_message_add_change_request_attribute(nr_stun_message *msg, UINT4 change_request)
+NR_STUN_MESSAGE_ADD_ATTRIBUTE(
+ NR_STUN_ATTR_OLD_CHANGE_REQUEST,
+ { attr->u.change_request = change_request; }
+)
+#endif /* USE_STUND_0_96 */
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_msg.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_msg.h
new file mode 100644
index 0000000000..ffd68d3eee
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_msg.h
@@ -0,0 +1,208 @@
+/*
+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_msg_h
+#define _stun_msg_h
+
+#include "csi_platform.h"
+#include "nr_api.h"
+#include "transport_addr.h"
+
+#define NR_STUN_MAX_USERNAME_BYTES 513
+#define NR_STUN_MAX_ERROR_CODE_REASON_BYTES 763
+#define NR_STUN_MAX_ERROR_CODE_REASON_CHARS 128
+#define NR_STUN_MAX_REALM_BYTES 763
+#define NR_STUN_MAX_REALM_CHARS 128
+#define NR_STUN_MAX_NONCE_BYTES 763
+#define NR_STUN_MAX_NONCE_CHARS 128
+#define NR_STUN_MAX_SERVER_BYTES 763
+#define NR_STUN_MAX_SERVER_CHARS 128
+#define NR_STUN_MAX_STRING_SIZE 763 /* any possible string */
+#define NR_STUN_MAX_UNKNOWN_ATTRIBUTES 16
+#define NR_STUN_MAX_MESSAGE_SIZE 2048
+
+#define NR_STUN_MAGIC_COOKIE 0x2112A442
+#define NR_STUN_MAGIC_COOKIE2 0xc5cb4e1d /* used recognize old stun messages */
+
+typedef struct { UCHAR octet[12]; } UINT12;
+
+typedef struct nr_stun_attr_error_code_ {
+ UINT2 number;
+ char reason[NR_STUN_MAX_ERROR_CODE_REASON_BYTES+1]; /* +1 for \0 */
+} nr_stun_attr_error_code;
+
+typedef struct nr_stun_attr_fingerprint_ {
+ UINT4 checksum;
+ int valid;
+} nr_stun_attr_fingerprint;
+
+typedef struct nr_stun_attr_message_integrity_ {
+ UCHAR hash[20];
+ int unknown_user;
+ UCHAR password[1024];
+ int passwordlen;
+ int valid;
+} nr_stun_attr_message_integrity;
+
+typedef struct nr_stun_attr_unknown_attributes_ {
+ UINT2 attribute[NR_STUN_MAX_UNKNOWN_ATTRIBUTES];
+ int num_attributes;
+} nr_stun_attr_unknown_attributes;
+
+typedef struct nr_stun_attr_xor_mapped_address_ {
+ nr_transport_addr masked;
+ nr_transport_addr unmasked;
+} nr_stun_attr_xor_mapped_address;
+
+typedef struct nr_stun_attr_data_ {
+ UCHAR data[NR_STUN_MAX_MESSAGE_SIZE];
+ size_t length;
+} nr_stun_attr_data;
+
+
+typedef struct nr_stun_encoded_attribute_ {
+ UINT2 type;
+ UINT2 length;
+ UCHAR value[NR_STUN_MAX_MESSAGE_SIZE];
+} nr_stun_encoded_attribute;
+
+typedef struct nr_stun_message_attribute_ {
+ UINT2 type;
+ UINT2 length;
+ union {
+ nr_transport_addr address;
+ nr_transport_addr alternate_server;
+ nr_stun_attr_error_code error_code;
+ nr_stun_attr_fingerprint fingerprint;
+ nr_transport_addr mapped_address;
+ nr_stun_attr_message_integrity message_integrity;
+ char nonce[NR_STUN_MAX_NONCE_BYTES+1]; /* +1 for \0 */
+ char realm[NR_STUN_MAX_REALM_BYTES+1]; /* +1 for \0 */
+ nr_stun_attr_xor_mapped_address relay_address;
+ char server_name[NR_STUN_MAX_SERVER_BYTES+1]; /* +1 for \0 */
+ nr_stun_attr_unknown_attributes unknown_attributes;
+ char username[NR_STUN_MAX_USERNAME_BYTES+1]; /* +1 for \0 */
+ nr_stun_attr_xor_mapped_address xor_mapped_address;
+
+#ifdef USE_ICE
+ UINT4 priority;
+ UINT8 ice_controlled;
+ UINT8 ice_controlling;
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+ UINT4 lifetime_secs;
+ nr_transport_addr remote_address;
+ UCHAR requested_transport;
+ nr_stun_attr_data data;
+#endif /* USE_TURN */
+
+#ifdef USE_STUND_0_96
+ UINT4 change_request;
+#endif /* USE_STUND_0_96 */
+
+ /* make sure there's enough room here to place any possible
+ * attribute */
+ UCHAR largest_possible_attribute[NR_STUN_MAX_MESSAGE_SIZE];
+ } u;
+ nr_stun_encoded_attribute *encoding;
+ size_t encoding_length;
+ char *name;
+ char *type_name;
+ int invalid;
+ TAILQ_ENTRY(nr_stun_message_attribute_) entry;
+} nr_stun_message_attribute;
+
+typedef TAILQ_HEAD(nr_stun_message_attribute_head_,nr_stun_message_attribute_) nr_stun_message_attribute_head;
+
+typedef struct nr_stun_message_header_ {
+ UINT2 type;
+ UINT2 length;
+ UINT4 magic_cookie;
+ UINT12 id;
+} nr_stun_message_header;
+
+typedef struct nr_stun_message_ {
+ char *name;
+ UCHAR buffer[NR_STUN_MAX_MESSAGE_SIZE];
+ size_t length;
+ nr_stun_message_header header;
+ int comprehension_required_unknown_attributes;
+ int comprehension_optional_unknown_attributes;
+ nr_stun_message_attribute_head attributes;
+} nr_stun_message;
+
+int nr_stun_message_create(nr_stun_message **msg);
+int nr_stun_message_create2(nr_stun_message **msg, UCHAR *buffer, size_t length);
+int nr_stun_message_destroy(nr_stun_message **msg);
+
+int nr_stun_message_attribute_create(nr_stun_message *msg, nr_stun_message_attribute **attr);
+int nr_stun_message_attribute_destroy(nr_stun_message *msg, nr_stun_message_attribute **attr);
+
+int nr_stun_message_has_attribute(nr_stun_message *msg, UINT2 type, nr_stun_message_attribute **attribute);
+
+int nr_stun_message_get_attribute(nr_stun_message *msg, UINT2 type, UINT2 index, nr_stun_message_attribute **attribute);
+
+int nr_stun_message_add_alternate_server_attribute(nr_stun_message *msg, nr_transport_addr *alternate_server);
+int nr_stun_message_add_error_code_attribute(nr_stun_message *msg, UINT2 number, char *reason);
+int nr_stun_message_add_fingerprint_attribute(nr_stun_message *msg);
+int nr_stun_message_add_message_integrity_attribute(nr_stun_message *msg, Data *password);
+int nr_stun_message_add_nonce_attribute(nr_stun_message *msg, char *nonce);
+int nr_stun_message_add_realm_attribute(nr_stun_message *msg, char *realm);
+int nr_stun_message_add_server_attribute(nr_stun_message *msg, char *server_name);
+int nr_stun_message_add_unknown_attributes_attribute(nr_stun_message *msg, nr_stun_attr_unknown_attributes *unknown_attributes);
+int nr_stun_message_add_username_attribute(nr_stun_message *msg, char *username);
+int nr_stun_message_add_xor_mapped_address_attribute(nr_stun_message *msg, nr_transport_addr *mapped_address);
+
+#ifdef USE_ICE
+int nr_stun_message_add_ice_controlled_attribute(nr_stun_message *msg, UINT8 ice_controlled);
+int nr_stun_message_add_ice_controlling_attribute(nr_stun_message *msg, UINT8 ice_controlling);
+int nr_stun_message_add_priority_attribute(nr_stun_message *msg, UINT4 priority);
+int nr_stun_message_add_use_candidate_attribute(nr_stun_message *msg);
+#endif /* USE_ICE */
+
+#ifdef USE_TURN
+int nr_stun_message_add_data_attribute(nr_stun_message *msg, UCHAR *data, int length);
+int nr_stun_message_add_lifetime_attribute(nr_stun_message *msg, UINT4 lifetime_secs);
+int nr_stun_message_add_requested_transport_attribute(nr_stun_message *msg, UCHAR transport);
+int
+nr_stun_message_add_xor_peer_address_attribute(nr_stun_message *msg, nr_transport_addr *peer_address);
+#endif /* USE_TURN */
+
+#ifdef USE_STUND_0_96
+int nr_stun_message_add_change_request_attribute(nr_stun_message *msg, UINT4 change_request);
+#endif /* USE_STUND_0_96 */
+
+#endif
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_proc.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_proc.c
new file mode 100644
index 0000000000..13366e265d
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_proc.c
@@ -0,0 +1,554 @@
+/*
+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.
+*/
+
+#include <errno.h>
+#include <csi_platform.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <stdlib.h>
+#include <io.h>
+#include <time.h>
+#else /* UNIX */
+#include <string.h>
+#endif /* end UNIX */
+#include <assert.h>
+
+#include "stun.h"
+#include "stun_reg.h"
+#include "registry.h"
+
+static int
+nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res);
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 7.3 */
+int
+nr_stun_receive_message(nr_stun_message *req, nr_stun_message *msg)
+{
+ int _status;
+ nr_stun_message_attribute *attr;
+
+#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
+ /* if this message was generated by an RFC 3489 impementation,
+ * the call to nr_is_stun_message will fail, so skip that
+ * check and puke elsewhere if the message can't be decoded */
+ if (msg->header.magic_cookie == NR_STUN_MAGIC_COOKIE
+ || msg->header.magic_cookie == NR_STUN_MAGIC_COOKIE2) {
+#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
+ if (!nr_is_stun_message(msg->buffer, msg->length)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Not a STUN message");
+ ABORT(R_REJECTED);
+ }
+#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
+ }
+#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
+
+ if (req == 0) {
+ if (NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_REQUEST) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"Illegal message type: %03x", msg->header.type);
+ ABORT(R_REJECTED);
+ }
+ }
+ else {
+ if (NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_RESPONSE
+ && NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_ERROR_RESPONSE) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"Illegal message class: %03x", msg->header.type);
+ ABORT(R_REJECTED);
+ }
+
+ if (NR_STUN_GET_TYPE_METHOD(req->header.type) != NR_STUN_GET_TYPE_METHOD(msg->header.type)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"Inconsistent message method: %03x expected %03x", msg->header.type, req->header.type);
+ ABORT(R_REJECTED);
+ }
+
+ if (nr_stun_different_transaction(msg->buffer, msg->length, req)) {
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized STUN transaction");
+ ABORT(R_REJECTED);
+ }
+ }
+
+ switch (msg->header.magic_cookie) {
+ case NR_STUN_MAGIC_COOKIE:
+ /* basically draft-ietf-behave-rfc3489bis-10.txt S 6 rules */
+
+ if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT, &attr)
+ && !attr->u.fingerprint.valid) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Invalid fingerprint");
+ ABORT(R_REJECTED);
+ }
+
+ break;
+
+#ifdef USE_STUND_0_96
+ case NR_STUN_MAGIC_COOKIE2:
+ /* nothing to check in this case */
+ break;
+#endif /* USE_STUND_0_96 */
+
+ default:
+#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
+ /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
+#else
+#ifdef NDEBUG
+ /* in deployment builds we should always see a recognized magic cookie */
+ r_log(NR_LOG_STUN, LOG_WARNING, "Missing Magic Cookie");
+ ABORT(R_REJECTED);
+#else
+ /* ignore this condition because sometimes we like to pretend we're
+ * a server talking to old clients and their messages don't contain
+ * a magic cookie at all but rather the magic cookie field is part
+ * of their ID and therefore random */
+#endif /* NDEBUG */
+#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
+ break;
+ }
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1 */
+int
+nr_stun_process_request(nr_stun_message *req, nr_stun_message *res)
+{
+ int _status;
+#ifdef USE_STUN_PEDANTIC
+ int r;
+ nr_stun_attr_unknown_attributes unknown_attributes = { { 0 } };
+ nr_stun_message_attribute *attr;
+
+ if (req->comprehension_required_unknown_attributes > 0) {
+ nr_stun_form_error_response(req, res, 420, "Unknown Attributes");
+ r_log(NR_LOG_STUN, LOG_WARNING, "Request contains comprehension required but unknown attributes");
+
+ TAILQ_FOREACH(attr, &req->attributes, entry) {
+ if (attr->name == 0) {
+ /* unrecognized attribute */
+
+ /* should never happen, but truncate if it ever were to occur */
+ if (unknown_attributes.num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES)
+ break;
+
+ unknown_attributes.attribute[unknown_attributes.num_attributes++] = attr->type;
+ }
+ }
+
+ assert(req->comprehension_required_unknown_attributes + req->comprehension_optional_unknown_attributes == unknown_attributes.num_attributes);
+
+ if ((r=nr_stun_message_add_unknown_attributes_attribute(res, &unknown_attributes)))
+ ABORT(R_ALREADY);
+
+ ABORT(R_ALREADY);
+ }
+#endif /* USE_STUN_PEDANTIC */
+
+ _status=0;
+#ifdef USE_STUN_PEDANTIC
+ abort:
+#endif /* USE_STUN_PEDANTIC */
+ return _status;
+}
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 7.3.2 */
+int
+nr_stun_process_indication(nr_stun_message *ind)
+{
+ int _status;
+#ifdef USE_STUN_PEDANTIC
+
+ if (ind->comprehension_required_unknown_attributes > 0) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Indication contains comprehension required but unknown attributes");
+ ABORT(R_REJECTED);
+ }
+#endif /* USE_STUN_PEDANTIC */
+
+ _status=0;
+#ifdef USE_STUN_PEDANTIC
+ abort:
+#endif /* USE_STUN_PEDANTIC */
+ return _status;
+}
+
+/* RFC5389 S 7.3.3, except that we *also* allow a MAPPED_ADDRESS
+ to compensate for a bug in Google's STUN server where it
+ always returns MAPPED_ADDRESS.
+
+ Mozilla bug: 888274.
+ */
+int
+nr_stun_process_success_response(nr_stun_message *res)
+{
+ int _status;
+
+#ifdef USE_STUN_PEDANTIC
+ if (res->comprehension_required_unknown_attributes > 0) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Response contains comprehension required but unknown attributes");
+ ABORT(R_REJECTED);
+ }
+#endif /* USE_STUN_PEDANTIC */
+
+ if (NR_STUN_GET_TYPE_METHOD(res->header.type) == NR_METHOD_BINDING) {
+ if (! nr_stun_message_has_attribute(res, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0) &&
+ ! nr_stun_message_has_attribute(res, NR_STUN_ATTR_MAPPED_ADDRESS, 0)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Missing XOR-MAPPED-ADDRESS and MAPPED_ADDRESS");
+ ABORT(R_REJECTED);
+ }
+ }
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 7.3.4 */
+int
+nr_stun_process_error_response(nr_stun_message *res, UINT2 *error_code)
+{
+ int _status;
+ nr_stun_message_attribute *attr;
+
+ if (res->comprehension_required_unknown_attributes > 0) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Error response contains comprehension required but unknown attributes");
+ ABORT(R_REJECTED);
+ }
+
+ if (! nr_stun_message_has_attribute(res, NR_STUN_ATTR_ERROR_CODE, &attr)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Missing ERROR-CODE");
+ ABORT(R_REJECTED);
+ }
+
+ *error_code = attr->u.error_code.number;
+
+ switch (attr->u.error_code.number / 100) {
+ case 3:
+ /* We do not treat STUN/300 as retryable. The TURN Allocate handling
+ * code will reset the ctx if appropriate. */
+ ABORT(R_REJECTED);
+ break;
+
+ case 4:
+ /* If the error code is 400 through 499, the client declares the
+ * transaction failed; in the case of 420 (Unknown Attribute), the
+ * response should contain a UNKNOWN-ATTRIBUTES attribute that gives
+ * additional information. */
+ if (attr->u.error_code.number == 420)
+ ABORT(R_REJECTED);
+
+ /* it may be possible to restart given the info that was received in
+ * this response, so retry */
+ ABORT(R_RETRY);
+ break;
+
+ case 5:
+ /* If the error code is 500 through 599, the client MAY resend the
+ * request; clients that do so MUST limit the number of times they do
+ * this. */
+ /* let the retransmit mechanism handle resending the request */
+ break;
+
+ default:
+ ABORT(R_REJECTED);
+ break;
+ }
+
+ /* the spec says: "The client then does any processing specified by the authentication
+ * mechanism (see Section 10). This may result in a new transaction
+ * attempt." -- but this is handled already elsewhere, so needn't be repeated
+ * in this function */
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 10.1.2 */
+int
+nr_stun_receive_request_or_indication_short_term_auth(nr_stun_message *msg,
+ nr_stun_message *res)
+{
+ int _status;
+ nr_stun_message_attribute *attr;
+
+ switch (msg->header.magic_cookie) {
+ default:
+ /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
+ /* drop thru */
+ case NR_STUN_MAGIC_COOKIE:
+ if (!nr_stun_message_has_attribute(msg, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
+ nr_stun_form_error_response(msg, res, 400, "Missing MESSAGE-INTEGRITY");
+ ABORT(R_ALREADY);
+ }
+
+ if (!nr_stun_message_has_attribute(msg, NR_STUN_ATTR_USERNAME, 0)) {
+ nr_stun_form_error_response(msg, res, 400, "Missing USERNAME");
+ ABORT(R_ALREADY);
+ }
+
+ if (attr->u.message_integrity.unknown_user) {
+ nr_stun_form_error_response(msg, res, 401, "Unrecognized USERNAME");
+ ABORT(R_ALREADY);
+ }
+
+ if (!attr->u.message_integrity.valid) {
+ nr_stun_form_error_response(msg, res, 401, "Bad MESSAGE-INTEGRITY");
+ ABORT(R_ALREADY);
+ }
+
+ break;
+
+#ifdef USE_STUND_0_96
+ case NR_STUN_MAGIC_COOKIE2:
+ /* nothing to check in this case */
+ break;
+#endif /* USE_STUND_0_96 */
+ }
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 10.1.3 */
+int
+nr_stun_receive_response_short_term_auth(nr_stun_message *res)
+{
+ int _status;
+ nr_stun_message_attribute *attr;
+
+ switch (res->header.magic_cookie) {
+ default:
+ /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
+ /* drop thru */
+ case NR_STUN_MAGIC_COOKIE:
+ if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Missing MESSAGE-INTEGRITY");
+ ABORT(R_REJECTED);
+ }
+
+ if (!attr->u.message_integrity.valid) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Bad MESSAGE-INTEGRITY");
+ ABORT(R_REJECTED);
+ }
+
+ break;
+
+#ifdef USE_STUND_0_96
+ case NR_STUN_MAGIC_COOKIE2:
+ /* nothing to check in this case */
+ break;
+#endif /* USE_STUND_0_96 */
+ }
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+static int
+nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res)
+{
+ int r,_status;
+ char *realm = 0;
+ char *nonce;
+ UINT2 size;
+
+ if ((r=NR_reg_alloc_string(NR_STUN_REG_PREF_SERVER_REALM, &realm)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_add_realm_attribute(res, realm)))
+ ABORT(r);
+
+ if (clnt) {
+ if (strlen(clnt->nonce) < 1)
+ new_nonce = 1;
+
+ if (new_nonce) {
+ if (NR_reg_get_uint2(NR_STUN_REG_PREF_SERVER_NONCE_SIZE, &size))
+ size = 48;
+
+ if (size > (sizeof(clnt->nonce) - 1))
+ size = sizeof(clnt->nonce) - 1;
+
+ nr_random_alphanum(clnt->nonce, size);
+ clnt->nonce[size] = '\0';
+ }
+
+ nonce = clnt->nonce;
+ }
+ else {
+ /* user is not known, so use a bogus nonce since there's no way to
+ * store a good nonce with the client-specific data -- this nonce
+ * will be recognized as stale if the client attempts another
+ * request */
+ nonce = "STALE";
+ }
+
+ if ((r=nr_stun_message_add_nonce_attribute(res, nonce)))
+ ABORT(r);
+
+ _status=0;
+ abort:
+#ifdef USE_TURN
+assert(_status == 0); /* TODO: !nn! cleanup after I reimplmement TURN */
+#endif
+ RFREE(realm);
+ return _status;
+}
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 10.2.1 - 10.2.2 */
+int
+nr_stun_receive_request_long_term_auth(nr_stun_message *req, nr_stun_server_ctx *ctx, nr_stun_message *res)
+{
+ int r,_status;
+ nr_stun_message_attribute *mi;
+ nr_stun_message_attribute *n;
+ nr_stun_server_client *clnt = 0;
+
+ switch (req->header.magic_cookie) {
+ default:
+ /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
+ /* drop thru */
+ case NR_STUN_MAGIC_COOKIE:
+ if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME, 0)) {
+ nr_stun_form_error_response(req, res, 400, "Missing USERNAME");
+ nr_stun_add_realm_and_nonce(0, 0, res);
+ ABORT(R_ALREADY);
+ }
+
+ if ((r=nr_stun_get_message_client(ctx, req, &clnt))) {
+ nr_stun_form_error_response(req, res, 401, "Unrecognized USERNAME");
+ nr_stun_add_realm_and_nonce(0, 0, res);
+ ABORT(R_ALREADY);
+ }
+
+ if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY, &mi)) {
+ nr_stun_form_error_response(req, res, 401, "Missing MESSAGE-INTEGRITY");
+ nr_stun_add_realm_and_nonce(0, clnt, res);
+ ABORT(R_ALREADY);
+ }
+
+ assert(!mi->u.message_integrity.unknown_user);
+
+ if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_REALM, 0)) {
+ nr_stun_form_error_response(req, res, 400, "Missing REALM");
+ ABORT(R_ALREADY);
+ }
+
+ if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_NONCE, &n)) {
+ nr_stun_form_error_response(req, res, 400, "Missing NONCE");
+ ABORT(R_ALREADY);
+ }
+
+ assert(sizeof(clnt->nonce) == sizeof(n->u.nonce));
+ if (strncmp(clnt->nonce, n->u.nonce, sizeof(n->u.nonce))) {
+ nr_stun_form_error_response(req, res, 438, "Stale NONCE");
+ nr_stun_add_realm_and_nonce(1, clnt, res);
+ ABORT(R_ALREADY);
+ }
+
+ if (!mi->u.message_integrity.valid) {
+ nr_stun_form_error_response(req, res, 401, "Bad MESSAGE-INTEGRITY");
+ nr_stun_add_realm_and_nonce(0, clnt, res);
+ ABORT(R_ALREADY);
+ }
+
+ break;
+
+#ifdef USE_STUND_0_96
+ case NR_STUN_MAGIC_COOKIE2:
+ /* nothing to do in this case */
+ break;
+#endif /* USE_STUND_0_96 */
+ }
+
+ _status=0;
+ abort:
+
+ return _status;
+}
+
+/* draft-ietf-behave-rfc3489bis-10.txt S 10.2.3 */
+int
+nr_stun_receive_response_long_term_auth(nr_stun_message *res, nr_stun_client_ctx *ctx)
+{
+ int _status;
+ nr_stun_message_attribute *attr;
+
+ switch (res->header.magic_cookie) {
+ default:
+ /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */
+ /* drop thru */
+ case NR_STUN_MAGIC_COOKIE:
+ if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_REALM, &attr)) {
+ RFREE(ctx->realm);
+ ctx->realm = r_strdup(attr->u.realm);
+ if (!ctx->realm)
+ ABORT(R_NO_MEMORY);
+ }
+ else {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Missing REALM");
+ ABORT(R_REJECTED);
+ }
+
+ if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_NONCE, &attr)) {
+ RFREE(ctx->nonce);
+ ctx->nonce = r_strdup(attr->u.nonce);
+ if (!ctx->nonce)
+ ABORT(R_NO_MEMORY);
+ }
+ else {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Missing NONCE");
+ ABORT(R_REJECTED);
+ }
+
+ if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) {
+ if (!attr->u.message_integrity.valid) {
+ r_log(NR_LOG_STUN, LOG_WARNING, "Bad MESSAGE-INTEGRITY");
+ ABORT(R_REJECTED);
+ }
+ }
+
+ break;
+
+#ifdef USE_STUND_0_96
+ case NR_STUN_MAGIC_COOKIE2:
+ /* nothing to check in this case */
+ break;
+#endif /* USE_STUND_0_96 */
+ }
+
+ _status=0;
+ abort:
+ return _status;
+}
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_proc.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_proc.h
new file mode 100644
index 0000000000..5975670779
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_proc.h
@@ -0,0 +1,53 @@
+/*
+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_proc_h
+#define _stun_proc_h
+
+#include "stun.h"
+
+int nr_stun_receive_message(nr_stun_message *req, nr_stun_message *msg);
+int nr_stun_process_request(nr_stun_message *req, nr_stun_message *res);
+int nr_stun_process_indication(nr_stun_message *ind);
+int nr_stun_process_success_response(nr_stun_message *res);
+int nr_stun_process_error_response(nr_stun_message *res, UINT2 *error_code);
+
+int nr_stun_receive_request_or_indication_short_term_auth(nr_stun_message *msg, nr_stun_message *res);
+int nr_stun_receive_response_short_term_auth(nr_stun_message *res);
+
+int nr_stun_receive_request_long_term_auth(nr_stun_message *req, nr_stun_server_ctx *ctx, nr_stun_message *res);
+int nr_stun_receive_response_long_term_auth(nr_stun_message *res, nr_stun_client_ctx *ctx);
+
+#endif
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_reg.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_reg.h
new file mode 100644
index 0000000000..2167fcd91b
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_reg.h
@@ -0,0 +1,58 @@
+/*
+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_reg_h
+#define _stun_reg_h
+#ifdef __cplusplus
+using namespace std;
+extern "C" {
+#endif /* __cplusplus */
+
+#define NR_STUN_REG_PREF_CLNT_RETRANSMIT_TIMEOUT "stun.client.retransmission_timeout"
+#define NR_STUN_REG_PREF_CLNT_RETRANSMIT_BACKOFF "stun.client.retransmission_backoff_factor"
+#define NR_STUN_REG_PREF_CLNT_MAXIMUM_TRANSMITS "stun.client.maximum_transmits"
+#define NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF "stun.client.final_retransmit_backoff"
+
+#define NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS "stun.allow_loopback"
+#define NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS "stun.allow_link_local"
+#define NR_STUN_REG_PREF_ADDRESS_PRFX "stun.address"
+#define NR_STUN_REG_PREF_SERVER_NAME "stun.server.name"
+#define NR_STUN_REG_PREF_SERVER_NONCE_SIZE "stun.server.nonce_size"
+#define NR_STUN_REG_PREF_SERVER_REALM "stun.server.realm"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_server_ctx.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_server_ctx.c
new file mode 100644
index 0000000000..b92b6b5ab6
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_server_ctx.c
@@ -0,0 +1,468 @@
+/*
+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.
+*/
+
+#include <string.h>
+#include <assert.h>
+
+#include "nr_api.h"
+#include "stun.h"
+
+static int nr_stun_server_destroy_client(nr_stun_server_client *clnt);
+static int nr_stun_server_send_response(nr_stun_server_ctx *ctx, nr_socket *sock, nr_transport_addr *peer_addr, nr_stun_message *res, nr_stun_server_client *clnt);
+static int nr_stun_server_process_request_auth_checks(nr_stun_server_ctx *ctx, nr_stun_message *req, int auth_rule, nr_stun_message *res);
+
+
+int nr_stun_server_ctx_create(char *label, nr_stun_server_ctx **ctxp)
+ {
+ int r,_status;
+ nr_stun_server_ctx *ctx=0;
+
+ if ((r=nr_stun_startup()))
+ ABORT(r);
+
+ if(!(ctx=RCALLOC(sizeof(nr_stun_server_ctx))))
+ ABORT(R_NO_MEMORY);
+
+ if(!(ctx->label=r_strdup(label)))
+ ABORT(R_NO_MEMORY);
+
+ STAILQ_INIT(&ctx->clients);
+
+ *ctxp=ctx;
+
+ _status=0;
+ abort:
+ return(_status);
+ }
+
+int nr_stun_server_ctx_destroy(nr_stun_server_ctx **ctxp)
+ {
+ nr_stun_server_ctx *ctx;
+ nr_stun_server_client *clnt1,*clnt2;
+
+ if(!ctxp || !*ctxp)
+ return(0);
+
+ ctx=*ctxp;
+
+ STAILQ_FOREACH_SAFE(clnt1, &ctx->clients, entry, clnt2) {
+ nr_stun_server_destroy_client(clnt1);
+ }
+
+ nr_stun_server_destroy_client(ctx->default_client);
+
+ RFREE(ctx->label);
+ RFREE(ctx);
+
+ return(0);
+ }
+
+static int nr_stun_server_client_create(nr_stun_server_ctx *ctx, char *client_label, char *user, Data *pass, nr_stun_server_cb cb, void *cb_arg, nr_stun_server_client **clntp)
+ {
+ nr_stun_server_client *clnt=0;
+ int r,_status;
+
+ if(!(clnt=RCALLOC(sizeof(nr_stun_server_client))))
+ ABORT(R_NO_MEMORY);
+
+ if(!(clnt->label=r_strdup(client_label)))
+ ABORT(R_NO_MEMORY);
+
+ if(!(clnt->username=r_strdup(user)))
+ ABORT(R_NO_MEMORY);
+
+ if(r=r_data_copy(&clnt->password,pass))
+ ABORT(r);
+
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-SERVER(%s)/CLIENT(%s): Adding client for %s",ctx->label, client_label, user);
+ clnt->stun_server_cb=cb;
+ clnt->cb_arg=cb_arg;
+
+ *clntp = clnt;
+ _status=0;
+ abort:
+ if(_status){
+ nr_stun_server_destroy_client(clnt);
+ }
+ return(_status);
+ }
+
+int nr_stun_server_add_client(nr_stun_server_ctx *ctx, char *client_label, char *user, Data *pass, nr_stun_server_cb cb, void *cb_arg)
+ {
+ int r,_status;
+ nr_stun_server_client *clnt;
+
+ if (r=nr_stun_server_client_create(ctx, client_label, user, pass, cb, cb_arg, &clnt))
+ ABORT(r);
+
+ STAILQ_INSERT_TAIL(&ctx->clients,clnt,entry);
+
+ _status=0;
+ abort:
+ return(_status);
+ }
+
+int nr_stun_server_add_default_client(nr_stun_server_ctx *ctx, char *ufrag, Data *pass, nr_stun_server_cb cb, void *cb_arg)
+ {
+ int r,_status;
+ nr_stun_server_client *clnt;
+
+ assert(!ctx->default_client);
+ if (ctx->default_client)
+ ABORT(R_INTERNAL);
+
+ if (r=nr_stun_server_client_create(ctx, "default_client", ufrag, pass, cb, cb_arg, &clnt))
+ ABORT(r);
+
+ ctx->default_client = clnt;
+
+ _status=0;
+ abort:
+ return(_status);
+ }
+
+int nr_stun_server_remove_client(nr_stun_server_ctx *ctx, void *cb_arg)
+ {
+ nr_stun_server_client *clnt1,*clnt2;
+ int found = 0;
+
+ STAILQ_FOREACH_SAFE(clnt1, &ctx->clients, entry, clnt2) {
+ if(clnt1->cb_arg == cb_arg) {
+ STAILQ_REMOVE(&ctx->clients, clnt1, nr_stun_server_client_, entry);
+ nr_stun_server_destroy_client(clnt1);
+ found++;
+ }
+ }
+
+ if (!found)
+ ERETURN(R_NOT_FOUND);
+
+ return 0;
+ }
+
+static int nr_stun_server_get_password(void *arg, nr_stun_message *msg, Data **password)
+ {
+ int _status;
+ nr_stun_server_ctx *ctx = (nr_stun_server_ctx*)arg;
+ nr_stun_server_client *clnt = 0;
+ nr_stun_message_attribute *username_attribute;
+
+ if ((nr_stun_get_message_client(ctx, msg, &clnt))) {
+ if (! nr_stun_message_has_attribute(msg, NR_STUN_ATTR_USERNAME, &username_attribute)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-SERVER(%s): Missing Username",ctx->label);
+ ABORT(R_NOT_FOUND);
+ }
+
+ /* Although this is an exceptional condition, we'll already have seen a
+ * NOTICE-level log message about the unknown user, so additional log
+ * messages at any level higher than DEBUG are unnecessary. */
+
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-SERVER(%s): Unable to find password for unknown user: %s",ctx->label,username_attribute->u.username);
+ ABORT(R_NOT_FOUND);
+ }
+
+ *password = &clnt->password;
+
+ _status=0;
+ abort:
+ return(_status);
+ }
+
+int nr_stun_server_process_request_auth_checks(nr_stun_server_ctx *ctx, nr_stun_message *req, int auth_rule, nr_stun_message *res)
+ {
+ int r,_status;
+
+ if (nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)
+ || !(auth_rule & NR_STUN_AUTH_RULE_OPTIONAL)) {
+ /* favor long term credentials over short term, if both are supported */
+
+ if (auth_rule & NR_STUN_AUTH_RULE_LONG_TERM) {
+ if ((r=nr_stun_receive_request_long_term_auth(req, ctx, res)))
+ ABORT(r);
+ }
+ else if (auth_rule & NR_STUN_AUTH_RULE_SHORT_TERM) {
+ if ((r=nr_stun_receive_request_or_indication_short_term_auth(req, res)))
+ ABORT(r);
+ }
+ }
+
+ _status=0;
+ abort:
+ return(_status);
+ }
+
+int nr_stun_server_process_request(nr_stun_server_ctx *ctx, nr_socket *sock, char *msg, int len, nr_transport_addr *peer_addr, int auth_rule)
+ {
+ int r,_status;
+ char string[256];
+ nr_stun_message *req = 0;
+ nr_stun_message *res = 0;
+ nr_stun_server_client *clnt = 0;
+ nr_stun_server_request info;
+ int error;
+ int dont_free = 0;
+ nr_transport_addr my_addr;
+
+ if ((r=nr_socket_getaddr(sock, &my_addr))) {
+ ABORT(r);
+ }
+
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-SERVER(%s): Received(my_addr=%s,peer_addr=%s)",ctx->label,my_addr.as_string,peer_addr->as_string);
+
+ snprintf(string, sizeof(string)-1, "STUN-SERVER(%s): Received ", ctx->label);
+ r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)msg, len);
+
+ memset(&info,0,sizeof(info));
+
+ if ((r=nr_stun_message_create2(&req, (UCHAR*)msg, len)))
+ ABORT(r);
+
+ if ((r=nr_stun_message_create(&res)))
+ ABORT(r);
+
+ if ((r=nr_stun_decode_message(req, nr_stun_server_get_password, ctx))) {
+ /* RFC5389 S 7.3 says "If any errors are detected, the message is
+ * silently discarded." */
+#ifndef USE_STUN_PEDANTIC
+ /* ... but that seems like a bad idea, at least return a 400 so
+ * that the server isn't a black hole to the client */
+ nr_stun_form_error_response(req, res, 400, "Bad Request - Failed to decode request");
+ ABORT(R_ALREADY);
+#endif /* USE_STUN_PEDANTIC */
+ ABORT(R_REJECTED);
+ }
+
+ if ((r=nr_stun_receive_message(0, req))) {
+ /* RFC5389 S 7.3 says "If any errors are detected, the message is
+ * silently discarded." */
+#ifndef USE_STUN_PEDANTIC
+ /* ... but that seems like a bad idea, at least return a 400 so
+ * that the server isn't a black hole to the client */
+ nr_stun_form_error_response(req, res, 400, "Bad Request - Section 7.3 check failed");
+ ABORT(R_ALREADY);
+#endif /* USE_STUN_PEDANTIC */
+ ABORT(R_REJECTED);
+ }
+
+ if (NR_STUN_GET_TYPE_CLASS(req->header.type) != NR_CLASS_REQUEST
+ && NR_STUN_GET_TYPE_CLASS(req->header.type) != NR_CLASS_INDICATION) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-SERVER(%s): Illegal message type: %04x",ctx->label,req->header.type);
+ /* RFC5389 S 7.3 says "If any errors are detected, the message is
+ * silently discarded." */
+#ifndef USE_STUN_PEDANTIC
+ /* ... but that seems like a bad idea, at least return a 400 so
+ * that the server isn't a black hole to the client */
+ nr_stun_form_error_response(req, res, 400, "Bad Request - Unsupported message type");
+ ABORT(R_ALREADY);
+#endif /* USE_STUN_PEDANTIC */
+ ABORT(R_REJECTED);
+ }
+
+ /* "The STUN agent then does any checks that are required by a
+ * authentication mechanism that the usage has specified" */
+ if ((r=nr_stun_server_process_request_auth_checks(ctx, req, auth_rule, res)))
+ ABORT(r);
+
+ if (NR_STUN_GET_TYPE_CLASS(req->header.type) == NR_CLASS_INDICATION) {
+ if ((r=nr_stun_process_indication(req)))
+ ABORT(r);
+ }
+ else {
+ if ((r=nr_stun_process_request(req, res)))
+ ABORT(r);
+ }
+
+ assert(res->header.type == 0);
+
+ clnt = 0;
+ if (NR_STUN_GET_TYPE_CLASS(req->header.type) == NR_CLASS_REQUEST) {
+ if ((nr_stun_get_message_client(ctx, req, &clnt))) {
+ if ((r=nr_stun_form_success_response(req, peer_addr, 0, res)))
+ ABORT(r);
+ }
+ else {
+ if ((r=nr_stun_form_success_response(req, peer_addr, &clnt->password, res)))
+ ABORT(r);
+ }
+ }
+
+ if(clnt && clnt->stun_server_cb){
+ r_log(NR_LOG_STUN,LOG_DEBUG,"Entering STUN server callback");
+
+ /* Set up the info */
+ if(r=nr_transport_addr_copy(&info.src_addr,peer_addr))
+ ABORT(r);
+
+ info.request = req;
+ info.response = res;
+
+ error = 0;
+ dont_free = 0;
+ if (clnt->stun_server_cb(clnt->cb_arg,ctx,sock,&info,&dont_free,&error)) {
+ if (error == 0)
+ error = 500;
+
+ nr_stun_form_error_response(req, res, error, "ICE Failure");
+ ABORT(R_ALREADY);
+ }
+ }
+
+ _status=0;
+ abort:
+ if (!res)
+ goto skip_response;
+
+ if (NR_STUN_GET_TYPE_CLASS(req->header.type) == NR_CLASS_INDICATION)
+ goto skip_response;
+
+ /* Now respond */
+
+ if (_status != 0 && ! nr_stun_message_has_attribute(res, NR_STUN_ATTR_ERROR_CODE, 0))
+ nr_stun_form_error_response(req, res, 500, "Failed to specify error");
+
+ if ((r=nr_stun_server_send_response(ctx, sock, peer_addr, res, clnt))) {
+ r_log(NR_LOG_STUN,LOG_ERR,"STUN-SERVER(label=%s): Failed sending response (my_addr=%s,peer_addr=%s)",ctx->label,my_addr.as_string,peer_addr->as_string);
+ _status = R_FAILED;
+ }
+
+#if 0
+ /* EKR: suppressed these checks because if you have an error when
+ you are sending an error, things go wonky */
+#ifdef SANITY_CHECKS
+ if (_status == R_ALREADY) {
+ assert(NR_STUN_GET_TYPE_CLASS(res->header.type) == NR_CLASS_ERROR_RESPONSE);
+ assert(nr_stun_message_has_attribute(res, NR_STUN_ATTR_ERROR_CODE, 0));
+ }
+ else {
+ assert(NR_STUN_GET_TYPE_CLASS(res->header.type) == NR_CLASS_RESPONSE);
+ assert(!nr_stun_message_has_attribute(res, NR_STUN_ATTR_ERROR_CODE, 0));
+ }
+#endif /* SANITY_CHECKS */
+#endif
+
+ if (0) {
+ skip_response:
+ _status = 0;
+ }
+
+ if (!dont_free) {
+ nr_stun_message_destroy(&res);
+ nr_stun_message_destroy(&req);
+ }
+
+ return(_status);
+ }
+
+static int nr_stun_server_send_response(nr_stun_server_ctx *ctx, nr_socket *sock, nr_transport_addr *peer_addr, nr_stun_message *res, nr_stun_server_client *clnt)
+ {
+ int r,_status;
+ char string[256];
+ nr_transport_addr my_addr;
+
+ if ((r=nr_socket_getaddr(sock, &my_addr))) {
+ ABORT(r);
+ }
+
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-SERVER(label=%s): Sending(my_addr=%s,peer_addr=%s)",ctx->label,my_addr.as_string,peer_addr->as_string);
+
+ if ((r=nr_stun_encode_message(res))) {
+ /* should never happen */
+ r_log(NR_LOG_STUN,LOG_ERR,"STUN-SERVER(label=%s): Unable to encode message", ctx->label);
+ }
+ else {
+ snprintf(string, sizeof(string)-1, "STUN(%s): Sending to %s ", ctx->label, peer_addr->as_string);
+ r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)res->buffer, res->length);
+
+ if(r=nr_socket_sendto(sock,res->buffer,res->length,0,peer_addr))
+ ABORT(r);
+ }
+
+ _status=0;
+ abort:
+ return(_status);
+ }
+
+static int nr_stun_server_destroy_client(nr_stun_server_client *clnt)
+ {
+ if (!clnt)
+ return 0;
+
+ RFREE(clnt->label);
+ RFREE(clnt->username);
+ r_data_zfree(&clnt->password);
+
+ RFREE(clnt);
+ return(0);
+ }
+
+int nr_stun_get_message_client(nr_stun_server_ctx *ctx, nr_stun_message *req, nr_stun_server_client **out)
+ {
+ int _status;
+ nr_stun_message_attribute *attr;
+ nr_stun_server_client *clnt=0;
+
+ if (! nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME, &attr)) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-SERVER(%s): Missing Username",ctx->label);
+ ABORT(R_NOT_FOUND);
+ }
+
+ STAILQ_FOREACH(clnt, &ctx->clients, entry) {
+ if (!strncmp(clnt->username, attr->u.username,
+ sizeof(attr->u.username)))
+ break;
+ }
+
+ if (!clnt && ctx->default_client) {
+ /* If we can't find a specific client see if this matches the default,
+ which means that the username starts with our ufrag.
+ */
+ char *colon = strchr(attr->u.username, ':');
+ if (colon && !strncmp(ctx->default_client->username,
+ attr->u.username,
+ colon - attr->u.username)) {
+ clnt = ctx->default_client;
+ r_log(NR_LOG_STUN,LOG_NOTICE,"STUN-SERVER(%s): Falling back to default client, username=: %s",ctx->label,attr->u.username);
+ }
+ }
+
+ if (!clnt) {
+ r_log(NR_LOG_STUN,LOG_WARNING,"STUN-SERVER(%s): Request from unknown user: %s",ctx->label,attr->u.username);
+ ABORT(R_NOT_FOUND);
+ }
+
+ *out = clnt;
+
+ _status=0;
+ abort:
+ return(_status);
+ }
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_server_ctx.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_server_ctx.h
new file mode 100644
index 0000000000..328675ee22
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_server_ctx.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 _stun_server_ctx_h
+#define _stun_server_ctx_h
+
+typedef struct nr_stun_server_ctx_ nr_stun_server_ctx;
+typedef struct nr_stun_server_client_ nr_stun_server_client;
+
+#include "stun_util.h"
+
+
+typedef struct nr_stun_server_request_{
+ nr_transport_addr src_addr;
+ nr_stun_message *request;
+ nr_stun_message *response;
+} nr_stun_server_request;
+
+typedef int (*nr_stun_server_cb)(void *cb_arg, struct nr_stun_server_ctx_ *ctx,nr_socket *sock,nr_stun_server_request *req, int *dont_free, int *error);
+
+struct nr_stun_server_client_ {
+ char *label;
+ char *username;
+ Data password;
+ nr_stun_server_cb stun_server_cb;
+ void *cb_arg;
+ char nonce[NR_STUN_MAX_NONCE_BYTES+1]; /* +1 for \0 */
+ STAILQ_ENTRY(nr_stun_server_client_) entry;
+};
+
+typedef STAILQ_HEAD(nr_stun_server_client_head_, nr_stun_server_client_) nr_stun_server_client_head;
+
+struct nr_stun_server_ctx_ {
+ char *label;
+ nr_stun_server_client_head clients;
+ nr_stun_server_client *default_client;
+};
+
+
+int nr_stun_server_ctx_create(char *label, nr_stun_server_ctx **ctxp);
+int nr_stun_server_ctx_destroy(nr_stun_server_ctx **ctxp);
+int nr_stun_server_add_client(nr_stun_server_ctx *ctx, char *client_label, char *user, Data *pass, nr_stun_server_cb cb, void *cb_arg);
+int nr_stun_server_remove_client(nr_stun_server_ctx *ctx, void *cb_arg);
+int nr_stun_server_add_default_client(nr_stun_server_ctx *ctx, char *ufrag, Data *pass, nr_stun_server_cb cb, void *cb_arg);
+int nr_stun_server_process_request(nr_stun_server_ctx *ctx, nr_socket *sock, char *msg, int len, nr_transport_addr *peer_addr, int auth_rule);
+int nr_stun_get_message_client(nr_stun_server_ctx *ctx, nr_stun_message *req, nr_stun_server_client **clnt);
+
+#endif
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_util.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_util.c
new file mode 100644
index 0000000000..cbb0128924
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_util.c
@@ -0,0 +1,352 @@
+/*
+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.
+*/
+
+#include <errno.h>
+#include <csi_platform.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <stdlib.h>
+#include <io.h>
+#include <time.h>
+#else /* UNIX */
+#include <string.h>
+#endif /* end UNIX */
+#include <assert.h>
+
+#include "stun.h"
+#include "stun_reg.h"
+#include "registry.h"
+#include "addrs.h"
+#include "transport_addr_reg.h"
+#include "nr_crypto.h"
+#include "hex.h"
+
+
+int NR_LOG_STUN = 0;
+
+int
+nr_stun_startup(void)
+{
+ int r,_status;
+
+ if ((r=r_log_register("stun", &NR_LOG_STUN)))
+ ABORT(r);
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+int
+nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to)
+{
+ int _status;
+
+ switch (from->ip_version) {
+ case NR_IPV4:
+ nr_ip4_port_to_transport_addr(
+ (ntohl(from->u.addr4.sin_addr.s_addr) ^ magicCookie),
+ (ntohs(from->u.addr4.sin_port) ^ (magicCookie>>16)),
+ from->protocol, to);
+ break;
+ case NR_IPV6:
+ {
+ union {
+ unsigned char addr[16];
+ UINT4 addr32[4];
+ } maskedAddr;
+
+ maskedAddr.addr32[0] = htonl(magicCookie); /* Passed in host byte order */
+ memcpy(&maskedAddr.addr32[1], transactionId.octet, sizeof(transactionId));
+
+ /* We now have the mask in network byte order */
+ /* Xor the address in network byte order */
+ for (size_t i = 0; i < sizeof(maskedAddr); ++i) {
+ maskedAddr.addr[i] ^= from->u.addr6.sin6_addr.s6_addr[i];
+ }
+
+ nr_ip6_port_to_transport_addr(
+ (struct in6_addr*)&maskedAddr,
+ (ntohs(from->u.addr6.sin6_port) ^ (magicCookie>>16)),
+ from->protocol, to);
+ }
+ break;
+ default:
+ assert(0);
+ ABORT(R_INTERNAL);
+ break;
+ }
+
+ _status = 0;
+ abort:
+ return _status;
+}
+
+int
+nr_stun_filter_local_addresses(nr_local_addr addrs[], int *count)
+{
+ int r,_status;
+ char allow_loopback = 0;
+ char allow_link_local = 0;
+
+ if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS,
+ &allow_loopback))) {
+ if (r != R_NOT_FOUND) {
+ ABORT(r);
+ }
+ }
+
+ if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS,
+ &allow_link_local))) {
+ if (r != R_NOT_FOUND) {
+ ABORT(r);
+ }
+ }
+
+ if ((r=nr_stun_filter_addrs(addrs,
+ !allow_loopback,
+ !allow_link_local,
+ count))) {
+ ABORT(r);
+ }
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+int
+nr_stun_find_local_addresses(nr_local_addr addrs[], int maxaddrs, int *count)
+{
+ int r,_status;
+ //NR_registry *children = 0;
+
+ *count = 0;
+
+#if 0
+ // this really goes with the code commented out below. (mjf)
+ if ((r=NR_reg_get_child_count(NR_STUN_REG_PREF_ADDRESS_PRFX, (unsigned int*)count)))
+ if (r != R_NOT_FOUND)
+ ABORT(r);
+#endif
+
+ if (*count == 0) {
+ if ((r=nr_stun_get_addrs(addrs, maxaddrs, count)))
+ ABORT(r);
+
+ goto done;
+ }
+
+ if (*count >= maxaddrs) {
+ r_log(NR_LOG_STUN, LOG_INFO, "Address list truncated from %d to %d", *count, maxaddrs);
+ *count = maxaddrs;
+ }
+
+#if 0
+ if (*count > 0) {
+ /* TODO(ekr@rtfm.com): Commented out 2012-07-26.
+
+ This code is currently not used in Firefox and needs to be
+ ported to 64-bit */
+ children = RCALLOC((*count + 10) * sizeof(*children));
+ if (!children)
+ ABORT(R_NO_MEMORY);
+
+ assert(sizeof(size_t) == sizeof(*count));
+
+ if ((r=NR_reg_get_children(NR_STUN_REG_PREF_ADDRESS_PRFX, children, (size_t)(*count + 10), (size_t*)count)))
+ ABORT(r);
+
+ for (i = 0; i < *count; ++i) {
+ if ((r=nr_reg_get_transport_addr(children[i], 0, &addrs[i].addr)))
+ ABORT(r);
+ }
+ }
+#endif
+
+ done:
+
+ _status=0;
+ abort:
+ //RFREE(children);
+ return _status;
+}
+
+int
+nr_stun_different_transaction(UCHAR *msg, size_t len, nr_stun_message *req)
+{
+ int _status;
+ nr_stun_message_header header;
+ char reqid[44];
+ char msgid[44];
+ size_t unused;
+
+ if (sizeof(header) > len)
+ ABORT(R_FAILED);
+
+ assert(sizeof(header.id) == sizeof(UINT12));
+
+ memcpy(&header, msg, sizeof(header));
+
+ if (memcmp(&req->header.id, &header.id, sizeof(header.id))) {
+ nr_nbin2hex((UCHAR*)&req->header.id, sizeof(req->header.id), reqid, sizeof(reqid), &unused);
+ nr_nbin2hex((UCHAR*)&header.id, sizeof(header.id), msgid, sizeof(msgid), &unused);
+ r_log(NR_LOG_STUN, LOG_DEBUG, "Mismatched message IDs %s/%s", reqid, msgid);
+ ABORT(R_NOT_FOUND);
+ }
+
+ _status=0;
+ abort:
+ return _status;
+}
+
+char*
+nr_stun_msg_type(int type)
+{
+ char *ret = 0;
+
+ switch (type) {
+ case NR_STUN_MSG_BINDING_REQUEST:
+ ret = "BINDING-REQUEST";
+ break;
+ case NR_STUN_MSG_BINDING_INDICATION:
+ ret = "BINDING-INDICATION";
+ break;
+ case NR_STUN_MSG_BINDING_RESPONSE:
+ ret = "BINDING-RESPONSE";
+ break;
+ case NR_STUN_MSG_BINDING_ERROR_RESPONSE:
+ ret = "BINDING-ERROR-RESPONSE";
+ break;
+
+#ifdef USE_TURN
+ case NR_STUN_MSG_ALLOCATE_REQUEST:
+ ret = "ALLOCATE-REQUEST";
+ break;
+ case NR_STUN_MSG_ALLOCATE_RESPONSE:
+ ret = "ALLOCATE-RESPONSE";
+ break;
+ case NR_STUN_MSG_ALLOCATE_ERROR_RESPONSE:
+ ret = "ALLOCATE-ERROR-RESPONSE";
+ break;
+ case NR_STUN_MSG_REFRESH_REQUEST:
+ ret = "REFRESH-REQUEST";
+ break;
+ case NR_STUN_MSG_REFRESH_RESPONSE:
+ ret = "REFRESH-RESPONSE";
+ break;
+ case NR_STUN_MSG_REFRESH_ERROR_RESPONSE:
+ ret = "REFRESH-ERROR-RESPONSE";
+ break;
+ case NR_STUN_MSG_SEND_INDICATION:
+ ret = "SEND-INDICATION";
+ break;
+ case NR_STUN_MSG_DATA_INDICATION:
+ ret = "DATA-INDICATION";
+ break;
+ case NR_STUN_MSG_PERMISSION_REQUEST:
+ ret = "PERMISSION-REQUEST";
+ break;
+ case NR_STUN_MSG_PERMISSION_RESPONSE:
+ ret = "PERMISSION-RESPONSE";
+ break;
+ case NR_STUN_MSG_PERMISSION_ERROR_RESPONSE:
+ ret = "PERMISSION-ERROR-RESPONSE";
+ break;
+#endif /* USE_TURN */
+
+ default:
+ /* ret remains 0 */
+ break;
+ }
+
+ return ret;
+}
+
+int
+nr_random_alphanum(char *alphanum, int size)
+{
+ static char alphanums[256] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };
+ int i;
+
+ nr_crypto_random_bytes((UCHAR*)alphanum, size);
+
+ /* now convert from binary to alphanumeric */
+ for (i = 0; i < size; ++i)
+ alphanum[i] = alphanums[(UCHAR)alphanum[i]];
+
+ return 0;
+}
+
+#ifndef UINT2_MAX
+#define UINT2_MAX ((UINT2)(65535U))
+#endif
+
+void nr_accumulate_count(UINT2* orig_count, UINT2 add_count)
+ {
+ if (UINT2_MAX - add_count < *orig_count) {
+ // don't rollover, just stop accumulating at MAX value
+ *orig_count = UINT2_MAX;
+ } else {
+ *orig_count += add_count;
+ }
+ }
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_util.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_util.h
new file mode 100644
index 0000000000..379b4fdd3d
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/stun_util.h
@@ -0,0 +1,62 @@
+/*
+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_util_h
+#define _stun_util_h
+
+#include "stun.h"
+#include "local_addr.h"
+
+extern int NR_LOG_STUN;
+
+int nr_stun_startup(void);
+
+int nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to);
+
+// removes duplicates, and based on prefs, loopback and link_local addresses
+int nr_stun_filter_local_addresses(nr_local_addr addrs[], int *count);
+
+int nr_stun_find_local_addresses(nr_local_addr addrs[], int maxaddrs, int *count);
+
+int nr_stun_different_transaction(UCHAR *msg, size_t len, nr_stun_message *req);
+
+char* nr_stun_msg_type(int type);
+
+int nr_random_alphanum(char *alphanum, int size);
+
+// accumulate a count without worrying about rollover
+void nr_accumulate_count(UINT2* orig_count, UINT2 add_count);
+
+#endif
+
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/turn_client_ctx.c b/dom/media/webrtc/transport/third_party/nICEr/src/stun/turn_client_ctx.c
new file mode 100644
index 0000000000..707d43a4a9
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/turn_client_ctx.c
@@ -0,0 +1,1277 @@
+/*
+ Copyright (c) 2007, Adobe Systems, Incorporated
+ Copyright (c) 2013, Mozilla
+
+ 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, Mozilla 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.
+*/
+
+#ifdef USE_TURN
+
+#include <assert.h>
+#include <string.h>
+
+#include "nr_api.h"
+#include "r_time.h"
+#include "async_timer.h"
+#include "nr_socket_buffered_stun.h"
+#include "stun.h"
+#include "turn_client_ctx.h"
+#include "ice_ctx.h"
+
+int NR_LOG_TURN = 0;
+
+#define TURN_MAX_PENDING_BYTES 32000
+
+#define TURN_RTO 100 /* Hardcoded RTO estimate */
+#define TURN_LIFETIME_REQUEST_SECONDS 3600 /* One hour */
+#define TURN_USECS_PER_S 1000000
+#define TURN_REFRESH_SLACK_SECONDS 10 /* How long before expiry to refresh
+ allocations/permissions. The RFC 5766
+ Section 7 recommendation if 60 seconds,
+ but this is silly since the transaction
+ times out after about 5. */
+#define TURN_PERMISSION_LIFETIME_SECONDS 300 /* 5 minutes. From RFC 5766 2.3 */
+
+// Set to enable a temporary fix that will run the TURN reservation keep-alive
+// logic when data is received via a TURN relayed path: a DATA_INDICATION packet is received.
+// TODO(pkerr@mozilla.com) This should be replace/removed when bug 935806 is implemented.
+#define REFRESH_RESERVATION_ON_RECV 1
+
+static int nr_turn_stun_ctx_create(nr_turn_client_ctx *tctx, int type,
+ NR_async_cb success_cb,
+ NR_async_cb failure_cb,
+ nr_turn_stun_ctx **ctxp);
+static int nr_turn_stun_ctx_destroy(nr_turn_stun_ctx **ctxp);
+static void nr_turn_stun_ctx_cb(NR_SOCKET s, int how, void *arg);
+static int nr_turn_stun_set_auth_params(nr_turn_stun_ctx *ctx,
+ char *realm, char *nonce);
+static void nr_turn_client_refresh_timer_cb(NR_SOCKET s, int how, void *arg);
+static int nr_turn_client_refresh_setup(nr_turn_client_ctx *ctx,
+ nr_turn_stun_ctx **sctx);
+static int nr_turn_client_start_refresh_timer(nr_turn_client_ctx *ctx,
+ nr_turn_stun_ctx *sctx,
+ UINT4 lifetime);
+static int nr_turn_permission_create(nr_turn_client_ctx *ctx,
+ const nr_transport_addr *addr,
+ nr_turn_permission **permp);
+static int nr_turn_permission_find(nr_turn_client_ctx *ctx,
+ const nr_transport_addr *addr,
+ nr_turn_permission **permp);
+static int nr_turn_permission_destroy(nr_turn_permission **permp);
+static void nr_turn_client_refresh_cb(NR_SOCKET s, int how, void *arg);
+static void nr_turn_client_permissions_cb(NR_SOCKET s, int how, void *cb);
+static int nr_turn_client_send_stun_request(nr_turn_client_ctx *ctx,
+ nr_stun_message *req,
+ int flags);
+
+int nr_transport_addr_listnode_create(const nr_transport_addr *addr, nr_transport_addr_listnode **listnodep)
+{
+ nr_transport_addr_listnode *listnode = 0;
+ int r,_status;
+
+ if (!(listnode=RCALLOC(sizeof(nr_transport_addr_listnode)))) {
+ ABORT(R_NO_MEMORY);
+ }
+
+ if ((r = nr_transport_addr_copy(&listnode->value, addr))) {
+ ABORT(r);
+ }
+
+ *listnodep = listnode;
+ listnode = 0;
+ _status = 0;
+
+abort:
+ nr_transport_addr_listnode_destroy(&listnode);
+ return(_status);
+}
+
+void nr_transport_addr_listnode_destroy(nr_transport_addr_listnode **listnode)
+{
+ RFREE(*listnode);
+ *listnode = 0;
+}
+
+/* nr_turn_stun_ctx functions */
+static int nr_turn_stun_ctx_create(nr_turn_client_ctx *tctx, int mode,
+ NR_async_cb success_cb,
+ NR_async_cb error_cb,
+ nr_turn_stun_ctx **ctxp)
+{
+ nr_turn_stun_ctx *sctx = 0;
+ int r,_status;
+ char label[256];
+
+ if (!(sctx=RCALLOC(sizeof(nr_turn_stun_ctx))))
+ ABORT(R_NO_MEMORY);
+
+ /* TODO(ekr@rtfm.com): label by phase */
+ snprintf(label, sizeof(label), "%s:%s", tctx->label, ":TURN");
+
+ if ((r=nr_stun_client_ctx_create(label, tctx->sock, &tctx->turn_server_addr,
+ TURN_RTO, &sctx->stun))) {
+ ABORT(r);
+ }
+
+ /* Set the STUN auth parameters, but don't set authentication on.
+ For that we need the nonce, set in nr_turn_stun_set_auth_params.
+ */
+ sctx->stun->auth_params.username=tctx->username;
+ INIT_DATA(sctx->stun->auth_params.password,
+ tctx->password->data, tctx->password->len);
+
+ sctx->tctx=tctx;
+ sctx->success_cb=success_cb;
+ sctx->error_cb=error_cb;
+ sctx->mode=mode;
+ sctx->last_error_code=0;
+ STAILQ_INIT(&sctx->addresses_tried);
+
+ /* Add ourselves to the tctx's list */
+ STAILQ_INSERT_TAIL(&tctx->stun_ctxs, sctx, entry);
+ *ctxp=sctx;
+
+ _status=0;
+abort:
+ if (_status) {
+ nr_turn_stun_ctx_destroy(&sctx);
+ }
+ return(_status);
+}
+
+/* Note: this function does not pull us off the tctx's list. */
+static int nr_turn_stun_ctx_destroy(nr_turn_stun_ctx **ctxp)
+{
+ nr_turn_stun_ctx *ctx;
+
+ if (!ctxp || !*ctxp)
+ return 0;
+
+ ctx = *ctxp;
+ *ctxp = 0;
+
+ nr_stun_client_ctx_destroy(&ctx->stun);
+ RFREE(ctx->realm);
+ RFREE(ctx->nonce);
+
+ while (!STAILQ_EMPTY(&ctx->addresses_tried)) {
+ nr_transport_addr_listnode *listnode = STAILQ_FIRST(&ctx->addresses_tried);
+ STAILQ_REMOVE_HEAD(&ctx->addresses_tried, entry);
+ nr_transport_addr_listnode_destroy(&listnode);
+ }
+
+ RFREE(ctx);
+
+ return 0;
+}
+
+static int nr_turn_stun_set_auth_params(nr_turn_stun_ctx *ctx,
+ char *realm, char *nonce)
+{
+ int _status;
+
+ RFREE(ctx->realm);
+ RFREE(ctx->nonce);
+
+ assert(realm);
+ if (!realm)
+ ABORT(R_BAD_ARGS);
+ ctx->realm=r_strdup(realm);
+ if (!ctx->realm)
+ ABORT(R_NO_MEMORY);
+
+ assert(nonce);
+ if (!nonce)
+ ABORT(R_BAD_ARGS);
+ ctx->nonce=r_strdup(nonce);
+ if (!ctx->nonce)
+ ABORT(R_NO_MEMORY);
+
+ RFREE(ctx->stun->realm);
+ ctx->stun->realm = r_strdup(ctx->realm);
+ if (!ctx->stun->realm)
+ ABORT(R_NO_MEMORY);
+
+ ctx->stun->auth_params.realm = ctx->realm;
+ ctx->stun->auth_params.nonce = ctx->nonce;
+ ctx->stun->auth_params.authenticate = 1; /* May already be 1 */
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+static int nr_turn_stun_ctx_start(nr_turn_stun_ctx *ctx)
+{
+ int r, _status;
+ nr_turn_client_ctx *tctx = ctx->tctx;
+ nr_transport_addr_listnode *address_tried = 0;
+
+ if ((r=nr_stun_client_reset(ctx->stun))) {
+ r_log(NR_LOG_TURN, LOG_ERR, "TURN(%s): Couldn't reset STUN",
+ tctx->label);
+ ABORT(r);
+ }
+
+ if ((r=nr_stun_client_start(ctx->stun, ctx->mode, nr_turn_stun_ctx_cb, ctx))) {
+ r_log(NR_LOG_TURN, LOG_ERR, "TURN(%s): Couldn't start STUN",
+ tctx->label);
+ ABORT(r);
+ }
+
+ if ((r=nr_transport_addr_listnode_create(&ctx->stun->peer_addr, &address_tried))) {
+ ABORT(r);
+ }
+
+ STAILQ_INSERT_TAIL(&ctx->addresses_tried, address_tried, entry);
+
+ _status=0;
+abort:
+ return _status;
+}
+
+static int nr_turn_stun_ctx_handle_redirect(nr_turn_stun_ctx *ctx)
+{
+ int r, _status;
+ nr_turn_client_ctx *tctx = ctx->tctx;
+ nr_stun_message_attribute *ec;
+ nr_stun_message_attribute *attr;
+ nr_transport_addr *alternate_addr = 0;
+ int index = 0;
+
+ if (!tctx->ctx) {
+ /* If we were to require TCP nr_sockets to allow multiple connect calls by
+ * disconnecting and re-connecting, we could avoid this requirement. */
+ r_log(NR_LOG_TURN, LOG_ERR,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect is not supported when "
+ "there is no ICE ctx, and by extension no socket factory, since we "
+ "need that to create new sockets in the TCP case",
+ tctx->label);
+ ABORT(R_BAD_ARGS);
+ }
+
+ if (ctx->stun->response->header.type != NR_STUN_MSG_ALLOCATE_ERROR_RESPONSE) {
+ r_log(NR_LOG_TURN, LOG_ERR,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect called for something "
+ "other than an Allocate error response (type=%d)",
+ tctx->label, ctx->stun->response->header.type);
+ ABORT(R_BAD_ARGS);
+ }
+
+ if (!nr_stun_message_has_attribute(ctx->stun->response,
+ NR_STUN_ATTR_ERROR_CODE, &ec) ||
+ (ec->u.error_code.number != 300)) {
+ r_log(NR_LOG_TURN, LOG_ERR,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect called without a "
+ "300 response",
+ tctx->label);
+ ABORT(R_BAD_ARGS);
+ }
+
+ while (!alternate_addr && !nr_stun_message_get_attribute(
+ ctx->stun->response, NR_STUN_ATTR_ALTERNATE_SERVER, index++, &attr)) {
+ alternate_addr = &attr->u.alternate_server;
+
+ // TODO: Someday we may need to handle IP version switching, but it is
+ // unclear how that is supposed to work with ICE when the IP version of
+ // the candidate's base address is fixed...
+ if (alternate_addr->ip_version != tctx->turn_server_addr.ip_version) {
+ r_log(NR_LOG_TURN, LOG_INFO,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect not trying %s, since it is a different IP version",
+ tctx->label, alternate_addr->as_string);
+ alternate_addr = 0;
+ continue;
+ }
+
+ /* Check if we've already tried this, and ignore if we have */
+ nr_transport_addr_listnode *address_tried = 0;
+ STAILQ_FOREACH(address_tried, &ctx->addresses_tried, entry) {
+ /* Ignore protocol */
+ alternate_addr->protocol = address_tried->value.protocol;
+ if (!nr_transport_addr_cmp(alternate_addr, &address_tried->value, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
+ r_log(NR_LOG_TURN, LOG_INFO,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect already tried %s, ignoring",
+ tctx->label, alternate_addr->as_string);
+ alternate_addr = 0;
+ break;
+ }
+ }
+ }
+
+ if (!alternate_addr) {
+ /* Should we use a different error code depending on why we didn't find
+ * one? (eg; no ALTERNATE-SERVERS at all, none that we have not tried
+ * already, none that are of a compatible IP version?) */
+ r_log(NR_LOG_TURN, LOG_ERR,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect did not find a viable "
+ "ALTERNATE-SERVER",
+ tctx->label);
+ ABORT(R_FAILED);
+ }
+
+ r_log(NR_LOG_TURN, LOG_INFO,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect trying %s",
+ tctx->label, alternate_addr->as_string);
+
+ /* This also handles the call to nr_transport_addr_fmt_addr_string */
+ if ((r = nr_transport_addr_copy_addrport(&tctx->turn_server_addr,
+ alternate_addr))) {
+ r_log(NR_LOG_TURN, LOG_ERR,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect copying ALTERNATE-SERVER "
+ "failed(%d)!",
+ tctx->label, r);
+ assert(0);
+ ABORT(r);
+ }
+
+ /* TURN server address is now updated. Restart the STUN Allocate ctx. Note
+ * that we do not attempt to update the local address; if the TURN server
+ * redirects to something that is not best reached from the already-selected
+ * local address, oh well. */
+
+ if (tctx->turn_server_addr.protocol == IPPROTO_TCP) {
+ /* For TCP, we need to replace the underlying nr_socket, since we cannot
+ * un-connect it from the old server. */
+ /* If we were to require TCP nr_sockets to allow multiple connect calls by
+ * disconnecting and re-connecting, we could avoid this stuff, and just
+ * call nr_socket_connect. */
+ nr_transport_addr old_local_addr;
+ nr_socket* new_socket;
+ if ((r = nr_socket_getaddr(tctx->sock, &old_local_addr))) {
+ r_log(NR_LOG_TURN, LOG_ERR,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect "
+ "failed to get old local address (%d)!",
+ tctx->label, r);
+ assert(0);
+ ABORT(r);
+ }
+
+ if ((r = nr_socket_factory_create_socket(tctx->ctx->socket_factory,
+ &old_local_addr, &new_socket))) {
+ r_log(NR_LOG_TURN, LOG_ERR,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect "
+ "failed to create new raw TCP socket for redirect (%d)!",
+ tctx->label, r);
+ assert(0);
+ ABORT(r);
+ }
+
+ if ((r = nr_socket_buffered_stun_reset(tctx->sock, new_socket))) {
+ /* nr_socket_buffered_stun_reset always takes ownership of |new_socket| */
+ r_log(NR_LOG_TURN, LOG_ERR,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect "
+ "failed to update raw TCP socket (%d)!",
+ tctx->label, r);
+ assert(0);
+ ABORT(r);
+ }
+
+ if ((r = nr_socket_connect(tctx->sock, &tctx->turn_server_addr))) {
+ if (r != R_WOULDBLOCK) {
+ r_log(NR_LOG_TURN, LOG_ERR,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect nr_socket_connect "
+ "failed(%d)!",
+ tctx->label, r);
+ assert(0);
+ ABORT(r);
+ }
+ }
+ }
+
+ nr_transport_addr_copy(&ctx->stun->peer_addr, &tctx->turn_server_addr);
+
+ if ((r = nr_turn_stun_ctx_start(ctx))) {
+ r_log(NR_LOG_TURN, LOG_ERR,
+ "TURN(%s): nr_turn_stun_ctx_handle_redirect nr_turn_stun_ctx_start "
+ "failed(%d)!",
+ tctx->label, r);
+ assert(0);
+ ABORT(r);
+ }
+
+ _status = 0;
+abort:
+ return _status;
+}
+
+static void nr_turn_stun_ctx_cb(NR_SOCKET s, int how, void *arg)
+{
+ int r, _status;
+ nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
+
+ ctx->last_error_code = ctx->stun->error_code;
+
+ switch (ctx->stun->state) {
+ case NR_STUN_CLIENT_STATE_DONE:
+ /* Save the realm and nonce */
+ if (ctx->stun->realm && (!ctx->tctx->realm || strcmp(ctx->stun->realm,
+ ctx->tctx->realm))) {
+ RFREE(ctx->tctx->realm);
+ ctx->tctx->realm = r_strdup(ctx->stun->realm);
+ if (!ctx->tctx->realm)
+ ABORT(R_NO_MEMORY);
+ }
+ if (ctx->stun->nonce && (!ctx->tctx->nonce || strcmp(ctx->stun->nonce,
+ ctx->tctx->nonce))) {
+ RFREE(ctx->tctx->nonce);
+ ctx->tctx->nonce = r_strdup(ctx->stun->nonce);
+ if (!ctx->tctx->nonce)
+ ABORT(R_NO_MEMORY);
+ }
+
+ ctx->retry_ct=0;
+ ctx->success_cb(0, 0, ctx);
+ break;
+
+ case NR_STUN_CLIENT_STATE_FAILED:
+ /* Special case: if this is an authentication error,
+ we retry once. This allows the 401/438 nonce retry
+ paradigm. After that, we fail */
+ /* TODO(ekr@rtfm.com): 401 needs a #define */
+ /* TODO(ekr@rtfm.com): Add alternate-server (Mozilla bug 857688) */
+ if (ctx->stun->error_code == 438) {
+ // track 438s for ice telemetry
+ nr_accumulate_count(&(ctx->tctx->cnt_438s), 1);
+ }
+ if (ctx->stun->error_code == 401 || ctx->stun->error_code == 438) {
+ if (ctx->retry_ct > 0) {
+ if (ctx->stun->error_code == 401) {
+ // track 401s for ice telemetry
+ nr_accumulate_count(&(ctx->tctx->cnt_401s), 1);
+ }
+ r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): Exceeded the number of retries", ctx->tctx->label);
+ ABORT(R_FAILED);
+ }
+
+ if (!ctx->stun->nonce) {
+ r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): 401 but no nonce", ctx->tctx->label);
+ ABORT(R_FAILED);
+ }
+ if (!ctx->stun->realm) {
+ r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): 401 but no realm", ctx->tctx->label);
+ ABORT(R_FAILED);
+ }
+
+ /* Try to retry */
+ if ((r=nr_turn_stun_set_auth_params(ctx, ctx->stun->realm,
+ ctx->stun->nonce)))
+ ABORT(r);
+
+ ctx->stun->error_code = 0; /* Reset to avoid inf-looping */
+
+ if ((r=nr_turn_stun_ctx_start(ctx))) {
+ r_log(NR_LOG_TURN, LOG_ERR, "TURN(%s): Couldn't start STUN", ctx->tctx->label);
+ ABORT(r);
+ }
+
+ ctx->retry_ct++;
+ } else if (ctx->stun->error_code == 300) {
+ r_log(NR_LOG_TURN, LOG_INFO,
+ "TURN(%s): Redirect received, restarting TURN", ctx->tctx->label);
+ /* We don't limit this with a retry counter, we limit redirects by
+ * checking whether we've tried the ALTERNATE-SERVER yet. */
+ ctx->retry_ct = 0;
+ if ((r = nr_turn_stun_ctx_handle_redirect(ctx))) {
+ ABORT(r);
+ }
+ } else {
+ ABORT(R_FAILED);
+ }
+ break;
+
+ case NR_STUN_CLIENT_STATE_TIMED_OUT:
+ ABORT(R_FAILED);
+ break;
+
+ case NR_STUN_CLIENT_STATE_CANCELLED:
+ assert(0); /* Shouldn't happen */
+ return;
+ break;
+
+ default:
+ assert(0); /* Shouldn't happen */
+ return;
+ }
+
+ _status=0;
+abort:
+ if (_status) {
+ ctx->error_cb(0, 0, ctx);
+ }
+}
+
+/* nr_turn_client_ctx functions */
+int nr_turn_client_ctx_create(const char* label, nr_socket* sock,
+ const char* username, Data* password,
+ nr_transport_addr* addr, nr_ice_ctx* ice_ctx,
+ nr_turn_client_ctx** ctxp) {
+ nr_turn_client_ctx *ctx=0;
+ int r,_status;
+
+ if ((r=r_log_register("turn", &NR_LOG_TURN)))
+ ABORT(r);
+
+ if(!(ctx=RCALLOC(sizeof(nr_turn_client_ctx))))
+ ABORT(R_NO_MEMORY);
+
+ STAILQ_INIT(&ctx->stun_ctxs);
+ STAILQ_INIT(&ctx->permissions);
+
+ if(!(ctx->label=r_strdup(label)))
+ ABORT(R_NO_MEMORY);
+
+ ctx->sock=sock;
+ ctx->username = r_strdup(username);
+ if (!ctx->username)
+ ABORT(R_NO_MEMORY);
+
+ if ((r=r_data_create(&ctx->password, password->data, password->len)))
+ ABORT(r);
+ if ((r=nr_transport_addr_copy(&ctx->turn_server_addr, addr)))
+ ABORT(r);
+
+ ctx->state = NR_TURN_CLIENT_STATE_INITTED;
+ if (addr->protocol == IPPROTO_TCP) {
+ if ((r=nr_socket_connect(ctx->sock, &ctx->turn_server_addr))) {
+ if (r != R_WOULDBLOCK)
+ ABORT(r);
+ }
+ }
+
+ ctx->ctx = ice_ctx;
+
+ *ctxp=ctx;
+
+ _status=0;
+abort:
+ if(_status){
+ nr_turn_client_ctx_destroy(&ctx);
+ }
+ return(_status);
+}
+
+int
+nr_turn_client_ctx_destroy(nr_turn_client_ctx **ctxp)
+{
+ nr_turn_client_ctx *ctx;
+
+ if(!ctxp || !*ctxp)
+ return(0);
+
+ ctx=*ctxp;
+ *ctxp = 0;
+
+ if (ctx->label)
+ r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): destroy", ctx->label);
+
+ nr_turn_client_deallocate(ctx);
+
+ /* Cancel frees the rest of our data */
+ RFREE(ctx->label);
+ ctx->label = 0;
+
+ nr_turn_client_cancel(ctx);
+
+ RFREE(ctx->username);
+ ctx->username = 0;
+ r_data_destroy(&ctx->password);
+ RFREE(ctx->nonce);
+ ctx->nonce = 0;
+ RFREE(ctx->realm);
+ ctx->realm = 0;
+
+ /* Destroy the STUN client ctxs */
+ while (!STAILQ_EMPTY(&ctx->stun_ctxs)) {
+ nr_turn_stun_ctx *stun = STAILQ_FIRST(&ctx->stun_ctxs);
+ STAILQ_REMOVE_HEAD(&ctx->stun_ctxs, entry);
+ nr_turn_stun_ctx_destroy(&stun);
+ }
+
+ /* Destroy the permissions */
+ while (!STAILQ_EMPTY(&ctx->permissions)) {
+ nr_turn_permission *perm = STAILQ_FIRST(&ctx->permissions);
+ STAILQ_REMOVE_HEAD(&ctx->permissions, entry);
+ nr_turn_permission_destroy(&perm);
+ }
+
+ RFREE(ctx);
+
+ return(0);
+}
+
+int nr_turn_client_cancel(nr_turn_client_ctx *ctx)
+{
+ nr_turn_stun_ctx *stun = 0;
+
+ if (ctx->state == NR_TURN_CLIENT_STATE_CANCELLED ||
+ ctx->state == NR_TURN_CLIENT_STATE_FAILED)
+ return(0);
+
+ if (ctx->label)
+ r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): cancelling", ctx->label);
+
+ /* Cancel the STUN client ctxs */
+ stun = STAILQ_FIRST(&ctx->stun_ctxs);
+ while (stun) {
+ nr_stun_client_cancel(stun->stun);
+ stun = STAILQ_NEXT(stun, entry);
+ }
+
+ /* Cancel the timers, if not already cancelled */
+ NR_async_timer_cancel(ctx->connected_timer_handle);
+ NR_async_timer_cancel(ctx->refresh_timer_handle);
+
+ ctx->state = NR_TURN_CLIENT_STATE_CANCELLED;
+
+ return(0);
+}
+
+int nr_turn_client_send_stun_request(nr_turn_client_ctx *ctx,
+ nr_stun_message *req,
+ int flags)
+{
+ int r,_status;
+
+ if ((r=nr_stun_encode_message(req)))
+ ABORT(r);
+
+ if ((r=nr_socket_sendto(ctx->sock,
+ req->buffer, req->length, flags,
+ &ctx->turn_server_addr))) {
+ r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): Failed sending request",
+ ctx->label);
+ ABORT(r);
+ }
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+int nr_turn_client_deallocate(nr_turn_client_ctx *ctx)
+{
+ int r,_status;
+ nr_stun_message *aloc = 0;
+ nr_stun_client_auth_params auth;
+ nr_stun_client_refresh_request_params refresh;
+
+ if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
+ return(0);
+
+ r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): deallocating", ctx->label);
+
+ refresh.lifetime_secs = 0;
+
+ auth.username = ctx->username;
+ INIT_DATA(auth.password, ctx->password->data, ctx->password->len);
+
+ auth.realm = ctx->realm;
+ auth.nonce = ctx->nonce;
+
+ auth.authenticate = 1;
+
+ if ((r=nr_stun_build_refresh_request(&auth, &refresh, &aloc)))
+ ABORT(r);
+
+ // We are only sending a single request here because we are in the process of
+ // shutting everything down. Theoretically we should probably start a seperate
+ // STUN transaction which outlives the TURN context.
+ if ((r=nr_turn_client_send_stun_request(ctx, aloc, 0)))
+ ABORT(r);
+
+ ctx->state = NR_TURN_CLIENT_STATE_DEALLOCATING;
+
+ _status=0;
+abort:
+ nr_stun_message_destroy(&aloc);
+ return(_status);
+}
+
+static void nr_turn_client_fire_finished_cb(nr_turn_client_ctx *ctx)
+ {
+ if (ctx->finished_cb) {
+ NR_async_cb finished_cb=ctx->finished_cb;
+ ctx->finished_cb=0;
+ finished_cb(0, 0, ctx->cb_arg);
+ }
+ }
+
+int nr_turn_client_failed(nr_turn_client_ctx *ctx)
+{
+ if (ctx->state == NR_TURN_CLIENT_STATE_FAILED ||
+ ctx->state == NR_TURN_CLIENT_STATE_CANCELLED)
+ return(0);
+
+ r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s) failed", ctx->label);
+ nr_turn_client_cancel(ctx);
+ ctx->state = NR_TURN_CLIENT_STATE_FAILED;
+ nr_turn_client_fire_finished_cb(ctx);
+
+ return(0);
+}
+
+int nr_turn_client_get_relayed_address(nr_turn_client_ctx *ctx,
+ nr_transport_addr *relayed_address)
+{
+ int r, _status;
+
+ if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
+ ABORT(R_FAILED);
+
+ if (r=nr_transport_addr_copy(relayed_address, &ctx->relay_addr))
+ ABORT(r);
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+int nr_turn_client_get_mapped_address(nr_turn_client_ctx *ctx,
+ nr_transport_addr *mapped_address)
+{
+ int r, _status;
+
+ if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
+ ABORT(R_FAILED);
+
+ if (r=nr_transport_addr_copy(mapped_address, &ctx->mapped_addr))
+ ABORT(r);
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+static void nr_turn_client_allocate_cb(NR_SOCKET s, int how, void *arg)
+{
+ nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
+ nr_turn_stun_ctx *refresh_ctx;
+ int r,_status;
+
+ ctx->tctx->state = NR_TURN_CLIENT_STATE_ALLOCATED;
+
+ if ((r=nr_transport_addr_copy(
+ &ctx->tctx->relay_addr,
+ &ctx->stun->results.allocate_response.relay_addr)))
+ ABORT(r);
+
+ if ((r=nr_transport_addr_copy(
+ &ctx->tctx->mapped_addr,
+ &ctx->stun->results.allocate_response.mapped_addr)))
+ ABORT(r);
+
+ if ((r=nr_turn_client_refresh_setup(ctx->tctx, &refresh_ctx)))
+ ABORT(r);
+
+ if ((r=nr_turn_client_start_refresh_timer(
+ ctx->tctx, refresh_ctx,
+ ctx->stun->results.allocate_response.lifetime_secs)))
+ ABORT(r);
+
+ r_log(NR_LOG_TURN, LOG_INFO,
+ "TURN(%s): Succesfully allocated addr %s lifetime=%u",
+ ctx->tctx->label,
+ ctx->tctx->relay_addr.as_string,
+ ctx->stun->results.allocate_response.lifetime_secs);
+
+ nr_turn_client_fire_finished_cb(ctx->tctx);
+ _status=0;
+abort:
+ if (_status) {
+ nr_turn_client_failed(ctx->tctx);
+ }
+}
+
+static void nr_turn_client_error_cb(NR_SOCKET s, int how, void *arg)
+{
+ nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
+
+ r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): mode %d, %s",
+ ctx->tctx->label, ctx->mode, __FUNCTION__);
+
+ nr_turn_client_failed(ctx->tctx);
+}
+
+static void nr_turn_client_permission_error_cb(NR_SOCKET s, int how, void *arg)
+{
+ nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
+
+ if (ctx->last_error_code == 403) {
+ // track 403s for ice telemetry
+ nr_accumulate_count(&(ctx->tctx->cnt_403s), 1);
+ r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): mode %d, permission denied",
+ ctx->tctx->label, ctx->mode);
+
+ } else{
+ nr_turn_client_error_cb(0, 0, ctx);
+ }
+}
+
+int nr_turn_client_allocate(nr_turn_client_ctx *ctx,
+ NR_async_cb finished_cb, void *cb_arg)
+{
+ nr_turn_stun_ctx *stun = 0;
+ int r,_status;
+
+ if(ctx->state == NR_TURN_CLIENT_STATE_FAILED ||
+ ctx->state == NR_TURN_CLIENT_STATE_CANCELLED){
+ /* TURN TCP contexts can fail before we ever try to form an allocation,
+ * since the TCP connection can fail. It is also conceivable that a TURN
+ * TCP context could be cancelled before we are done forming all
+ * allocations (although we do not do this at the time this code was
+ * written) */
+ assert(ctx->turn_server_addr.protocol == IPPROTO_TCP);
+ ABORT(R_NOT_FOUND);
+ }
+
+ assert(ctx->state == NR_TURN_CLIENT_STATE_INITTED);
+
+ ctx->finished_cb=finished_cb;
+ ctx->cb_arg=cb_arg;
+
+ if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST,
+ nr_turn_client_allocate_cb,
+ nr_turn_client_error_cb,
+ &stun)))
+ ABORT(r);
+ stun->stun->params.allocate_request.lifetime_secs =
+ TURN_LIFETIME_REQUEST_SECONDS;
+
+ if (ctx->state == NR_TURN_CLIENT_STATE_INITTED) {
+ if ((r=nr_turn_stun_ctx_start(stun)))
+ ABORT(r);
+ ctx->state = NR_TURN_CLIENT_STATE_ALLOCATING;
+ } else {
+ ABORT(R_ALREADY);
+ }
+
+ _status=0;
+abort:
+ if (_status) {
+ nr_turn_client_failed(ctx);
+ }
+
+ return(_status);
+}
+
+int nr_turn_client_process_response(nr_turn_client_ctx *ctx,
+ UCHAR *msg, int len,
+ nr_transport_addr *turn_server_addr)
+{
+ int r, _status;
+ nr_turn_stun_ctx *sc1;
+
+ switch (ctx->state) {
+ case NR_TURN_CLIENT_STATE_ALLOCATING:
+ case NR_TURN_CLIENT_STATE_ALLOCATED:
+ break;
+ default:
+ ABORT(R_FAILED);
+ }
+
+ sc1 = STAILQ_FIRST(&ctx->stun_ctxs);
+ while (sc1) {
+ r = nr_stun_client_process_response(sc1->stun, msg, len, turn_server_addr);
+ if (!r)
+ break;
+ if (r==R_RETRY) /* Likely a 401 and we will retry */
+ break;
+ if (r != R_REJECTED)
+ ABORT(r);
+ sc1 = STAILQ_NEXT(sc1, entry);
+ }
+ if (!sc1)
+ ABORT(R_REJECTED);
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+static int nr_turn_client_refresh_setup(nr_turn_client_ctx *ctx,
+ nr_turn_stun_ctx **sctx)
+{
+ nr_turn_stun_ctx *stun = 0;
+ int r,_status;
+
+ assert(ctx->state == NR_TURN_CLIENT_STATE_ALLOCATED);
+ if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
+ ABORT(R_NOT_PERMITTED);
+
+ if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_REFRESH_REQUEST,
+ nr_turn_client_refresh_cb,
+ nr_turn_client_error_cb,
+ &stun)))
+ ABORT(r);
+
+ if ((r=nr_turn_stun_set_auth_params(stun, ctx->realm, ctx->nonce)))
+ ABORT(r);
+
+ stun->stun->params.refresh_request.lifetime_secs =
+ TURN_LIFETIME_REQUEST_SECONDS;
+
+
+ *sctx=stun;
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+static int nr_turn_client_start_refresh_timer(nr_turn_client_ctx *tctx,
+ nr_turn_stun_ctx *sctx,
+ UINT4 lifetime)
+{
+ int _status;
+
+ assert(!tctx->refresh_timer_handle);
+
+ if (lifetime <= TURN_REFRESH_SLACK_SECONDS) {
+ r_log(NR_LOG_TURN, LOG_ERR, "Too short lifetime specified for turn %u", lifetime);
+ ABORT(R_BAD_DATA);
+ }
+
+ if (lifetime > 3600)
+ lifetime = 3600;
+
+ lifetime -= TURN_REFRESH_SLACK_SECONDS;
+
+ r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Setting refresh timer for %u seconds",
+ tctx->label, lifetime);
+ NR_ASYNC_TIMER_SET(lifetime * 1000, nr_turn_client_refresh_timer_cb, sctx,
+ &tctx->refresh_timer_handle);
+
+ _status=0;
+abort:
+ if (_status) {
+ nr_turn_client_failed(tctx);
+ }
+ return _status;
+}
+
+static void nr_turn_client_refresh_timer_cb(NR_SOCKET s, int how, void *arg)
+{
+ nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
+ int r,_status;
+
+ r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Refresh timer fired",
+ ctx->tctx->label);
+
+ ctx->tctx->refresh_timer_handle=0;
+ if ((r=nr_turn_stun_ctx_start(ctx))) {
+ ABORT(r);
+ }
+
+ _status=0;
+abort:
+ if (_status) {
+ nr_turn_client_failed(ctx->tctx);
+ }
+ return;
+}
+
+static void nr_turn_client_refresh_cb(NR_SOCKET s, int how, void *arg)
+{
+ int r, _status;
+ nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
+ /* Save lifetime from the reset */
+ UINT4 lifetime = ctx->stun->results.refresh_response.lifetime_secs;
+
+ r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Refresh succeeded. lifetime=%u",
+ ctx->tctx->label, lifetime);
+
+ if ((r=nr_turn_client_start_refresh_timer(
+ ctx->tctx, ctx, lifetime)))
+ ABORT(r);
+
+ _status=0;
+
+abort:
+ if (_status) {
+ nr_turn_client_failed(ctx->tctx);
+ }
+}
+
+/* TODO(ekr@rtfm.com): We currently don't support channels.
+ We might in the future. Mozilla bug 857736 */
+int nr_turn_client_send_indication(nr_turn_client_ctx *ctx,
+ const UCHAR *msg, size_t len,
+ int flags, const nr_transport_addr *remote_addr)
+{
+ int r,_status;
+ nr_stun_client_send_indication_params params = { { 0 } };
+ nr_stun_message *ind = 0;
+
+ if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
+ ABORT(R_FAILED);
+
+ r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Send indication len=%zu",
+ ctx->label, len);
+
+ if ((r=nr_turn_client_ensure_perm(ctx, remote_addr)))
+ ABORT(r);
+
+ if ((r=nr_transport_addr_copy(&params.remote_addr, remote_addr)))
+ ABORT(r);
+
+ params.data.data = (UCHAR*)msg;
+ params.data.len = len;
+
+ if ((r=nr_stun_build_send_indication(&params, &ind)))
+ ABORT(r);
+
+ if ((r=nr_turn_client_send_stun_request(ctx, ind, flags)))
+ ABORT(r);
+
+ _status=0;
+abort:
+ nr_stun_message_destroy(&ind);
+ return(_status);
+}
+
+int nr_turn_client_parse_data_indication(nr_turn_client_ctx *ctx,
+ nr_transport_addr *source_addr,
+ UCHAR *msg, size_t len,
+ UCHAR *newmsg, size_t *newlen,
+ size_t newsize,
+ nr_transport_addr *remote_addr)
+{
+ int r,_status;
+ nr_stun_message *ind=0;
+ nr_stun_message_attribute *attr;
+ nr_turn_permission *perm;
+
+ if (nr_transport_addr_cmp(&ctx->turn_server_addr, source_addr,
+ NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
+ r_log(NR_LOG_TURN, LOG_WARNING,
+ "TURN(%s): Indication from unexpected source addr %s (expected %s)",
+ ctx->label, source_addr->as_string, ctx->turn_server_addr.as_string);
+ ABORT(R_REJECTED);
+ }
+
+ if ((r=nr_stun_message_create2(&ind, msg, len)))
+ ABORT(r);
+ if ((r=nr_stun_decode_message(ind, 0, 0)))
+ ABORT(r);
+
+ if (ind->header.type != NR_STUN_MSG_DATA_INDICATION)
+ ABORT(R_BAD_ARGS);
+
+ if (!nr_stun_message_has_attribute(ind, NR_STUN_ATTR_XOR_PEER_ADDRESS, &attr))
+ ABORT(R_BAD_ARGS);
+
+ if ((r=nr_turn_permission_find(ctx, &attr->u.xor_mapped_address.unmasked,
+ &perm))) {
+ if (r == R_NOT_FOUND) {
+ r_log(NR_LOG_TURN, LOG_WARNING,
+ "TURN(%s): Indication from peer addr %s with no permission",
+ ctx->label, attr->u.xor_mapped_address.unmasked.as_string);
+ }
+ ABORT(r);
+ }
+
+ if ((r=nr_transport_addr_copy(remote_addr,
+ &attr->u.xor_mapped_address.unmasked)))
+ ABORT(r);
+
+#if REFRESH_RESERVATION_ON_RECV
+ if ((r=nr_turn_client_ensure_perm(ctx, remote_addr))) {
+ ABORT(r);
+ }
+#endif
+
+ if (!nr_stun_message_has_attribute(ind, NR_STUN_ATTR_DATA, &attr)) {
+ ABORT(R_BAD_DATA);
+ }
+
+ assert(newsize >= attr->u.data.length);
+ if (newsize < attr->u.data.length)
+ ABORT(R_BAD_ARGS);
+
+ memcpy(newmsg, attr->u.data.data, attr->u.data.length);
+ *newlen = attr->u.data.length;
+
+ _status=0;
+abort:
+ nr_stun_message_destroy(&ind);
+ return(_status);
+}
+
+
+
+/* The permissions model is as follows:
+
+ - We keep a list of all the permissions we have ever requested
+ along with when they were last established.
+ - Whenever someone sends a packet, we automatically create/
+ refresh the permission.
+
+ This means that permissions automatically time out if
+ unused.
+
+*/
+int nr_turn_client_ensure_perm(nr_turn_client_ctx *ctx, const nr_transport_addr *addr)
+{
+ int r, _status;
+ nr_turn_permission *perm = 0;
+ UINT8 now;
+ UINT8 turn_permission_refresh = (TURN_PERMISSION_LIFETIME_SECONDS -
+ TURN_REFRESH_SLACK_SECONDS) * TURN_USECS_PER_S;
+
+ if ((r=nr_turn_permission_find(ctx, addr, &perm))) {
+ if (r == R_NOT_FOUND) {
+ if ((r=nr_turn_permission_create(ctx, addr, &perm)))
+ ABORT(r);
+ }
+ else {
+ ABORT(r);
+ }
+ }
+
+ assert(perm);
+
+ /* Now check that the permission is up-to-date */
+ now = r_gettimeint();
+
+ if ((now - perm->last_used) > turn_permission_refresh) {
+ r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Permission for %s requires refresh",
+ ctx->label, perm->addr.as_string);
+
+ if ((r=nr_turn_stun_ctx_start(perm->stun)))
+ ABORT(r);
+
+ perm->last_used = now; /* Update the time now so we don't retry on
+ next packet */
+ }
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+static int nr_turn_permission_create(nr_turn_client_ctx *ctx, const nr_transport_addr *addr,
+ nr_turn_permission **permp)
+{
+ int r, _status;
+ nr_turn_permission *perm = 0;
+
+ assert(ctx->state == NR_TURN_CLIENT_STATE_ALLOCATED);
+
+ r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): Creating permission for %s",
+ ctx->label, addr->as_string);
+
+ if (!(perm = RCALLOC(sizeof(nr_turn_permission))))
+ ABORT(R_NO_MEMORY);
+
+ if ((r=nr_transport_addr_copy(&perm->addr, addr)))
+ ABORT(r);
+
+ perm->last_used = 0;
+
+ if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_PERMISSION_REQUEST,
+ nr_turn_client_permissions_cb,
+ nr_turn_client_permission_error_cb,
+ &perm->stun)))
+ ABORT(r);
+
+ /* We want to authenticate on the first packet */
+ if ((r=nr_turn_stun_set_auth_params(perm->stun, ctx->realm, ctx->nonce)))
+ ABORT(r);
+
+ if ((r=nr_transport_addr_copy(
+ &perm->stun->stun->params.permission_request.remote_addr, addr)))
+ ABORT(r);
+ STAILQ_INSERT_TAIL(&ctx->permissions, perm, entry);
+
+ *permp = perm;
+
+ _status=0;
+abort:
+ if (_status) {
+ nr_turn_permission_destroy(&perm);
+ }
+ return(_status);
+}
+
+
+static int nr_turn_permission_find(nr_turn_client_ctx *ctx, const nr_transport_addr *addr,
+ nr_turn_permission **permp)
+{
+ nr_turn_permission *perm;
+ int _status;
+
+ perm = STAILQ_FIRST(&ctx->permissions);
+ while (perm) {
+ if (!nr_transport_addr_cmp(&perm->addr, addr,
+ NR_TRANSPORT_ADDR_CMP_MODE_ADDR))
+ break;
+
+ perm = STAILQ_NEXT(perm, entry);
+ }
+
+ if (!perm) {
+ ABORT(R_NOT_FOUND);
+ }
+ if (perm->stun->last_error_code == 403) {
+ ABORT(R_NOT_PERMITTED);
+ }
+ *permp = perm;
+
+ _status=0;
+abort:
+ return(_status);
+}
+
+static void nr_turn_client_permissions_cb(NR_SOCKET s, int how, void *arg)
+{
+ nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
+ r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Successfully refreshed permission",
+ ctx->tctx->label);
+}
+
+/* Note that we don't destroy the nr_turn_stun_ctx. That is owned by the
+ nr_turn_client_ctx. */
+static int nr_turn_permission_destroy(nr_turn_permission **permp)
+{
+ nr_turn_permission *perm;
+
+ if (!permp || !*permp)
+ return(0);
+
+ perm = *permp;
+ *permp = 0;
+
+ RFREE(perm);
+
+ return(0);
+}
+
+#endif /* USE_TURN */
diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/stun/turn_client_ctx.h b/dom/media/webrtc/transport/third_party/nICEr/src/stun/turn_client_ctx.h
new file mode 100644
index 0000000000..2049f1bdfb
--- /dev/null
+++ b/dom/media/webrtc/transport/third_party/nICEr/src/stun/turn_client_ctx.h
@@ -0,0 +1,161 @@
+/*
+Copyright (c) 2007, Adobe Systems, Incorporated
+Copyright (c) 2013, Mozilla
+
+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, Mozilla 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 _turn_client_ctx_h
+#define _turn_client_ctx_h
+
+struct nr_ice_ctx_;
+
+typedef struct nr_transport_addr_listnode_ {
+ nr_transport_addr value;
+ STAILQ_ENTRY(nr_transport_addr_listnode_) entry;
+} nr_transport_addr_listnode;
+typedef STAILQ_HEAD(nr_transport_addr_listnode_head_, nr_transport_addr_listnode_) nr_transport_addr_listnode_head;
+
+/*
+ Represents a single set of STUN transactions, i.e.,
+ Allocate, Refresh, Permission. It automatically handles
+ permissions and restarts.
+ */
+typedef struct nr_turn_stun_ctx_ {
+ struct nr_turn_client_ctx_ *tctx;
+ int mode; /* From stun_client_ctx.h, NR_TURN_CLIENT_MODE_* */
+ int retry_ct;
+ nr_stun_client_ctx *stun;
+ char *nonce;
+ char *realm;
+ NR_async_cb success_cb;
+ NR_async_cb error_cb;
+ int last_error_code;
+
+ nr_transport_addr_listnode_head addresses_tried;
+
+ STAILQ_ENTRY(nr_turn_stun_ctx_) entry;
+} nr_turn_stun_ctx;
+typedef STAILQ_HEAD(nr_turn_stun_ctx_head_, nr_turn_stun_ctx_)
+ nr_turn_stun_ctx_head;
+
+/* Represents a single TURN permission */
+typedef struct nr_turn_permission_ {
+ nr_transport_addr addr;
+ nr_turn_stun_ctx *stun;
+ UINT8 last_used;
+
+ STAILQ_ENTRY(nr_turn_permission_) entry;
+} nr_turn_permission;
+typedef STAILQ_HEAD(nr_turn_permission_head_, nr_turn_permission_)
+ nr_turn_permission_head;
+
+/* A single connection to a TURN server. Use one
+ turn_client_ctx per socket/server pair. */
+typedef struct nr_turn_client_ctx_ {
+ int state;
+#define NR_TURN_CLIENT_STATE_INITTED 1
+#define NR_TURN_CLIENT_STATE_ALLOCATING 2
+#define NR_TURN_CLIENT_STATE_ALLOCATED 3
+#define NR_TURN_CLIENT_STATE_FAILED 4
+#define NR_TURN_CLIENT_STATE_CANCELLED 5
+#define NR_TURN_CLIENT_STATE_DEALLOCATING 6
+
+ char *label;
+ nr_socket *sock;
+
+ char *username;
+ Data *password;
+ char *nonce;
+ char *realm;
+
+ nr_transport_addr turn_server_addr;
+ nr_transport_addr relay_addr;
+ nr_transport_addr mapped_addr;
+
+ nr_turn_stun_ctx_head stun_ctxs;
+ nr_turn_permission_head permissions;
+
+ /* We need access to the socket factory to create new TCP sockets for handling
+ * STUN/300 responses. */
+ /* If we were to require TCP nr_sockets to allow multiple connect calls by
+ * disconnecting and re-connecting, we could avoid this requirement. */
+ struct nr_ice_ctx_* ctx;
+
+ NR_async_cb finished_cb;
+ void *cb_arg;
+
+ void *connected_timer_handle;
+ void *refresh_timer_handle;
+
+ // ice telemetry
+ UINT2 cnt_401s;
+ UINT2 cnt_403s;
+ UINT2 cnt_438s;
+} nr_turn_client_ctx;
+
+extern int NR_LOG_TURN;
+
+int nr_transport_addr_listnode_create(const nr_transport_addr *addr, nr_transport_addr_listnode **listnodep);
+void nr_transport_addr_listnode_destroy(nr_transport_addr_listnode **listnode);
+int nr_turn_client_ctx_create(const char* label, nr_socket* sock,
+ const char* username, Data* password,
+ nr_transport_addr* addr,
+ struct nr_ice_ctx_* ice_ctx,
+ nr_turn_client_ctx** ctxp);
+int nr_turn_client_ctx_destroy(nr_turn_client_ctx **ctxp);
+int nr_turn_client_allocate(nr_turn_client_ctx *ctx,
+ NR_async_cb finished_cb, void *cb_arg);
+int nr_turn_client_get_relayed_address(nr_turn_client_ctx *ctx,
+ nr_transport_addr *relayed_address);
+int nr_turn_client_get_mapped_address(nr_turn_client_ctx *ctx,
+ nr_transport_addr *mapped_address);
+int nr_turn_client_process_response(nr_turn_client_ctx *ctx,
+ UCHAR *msg, int len,
+ nr_transport_addr *turn_server_addr);
+int nr_turn_client_cancel(nr_turn_client_ctx *ctx);
+int nr_turn_client_failed(nr_turn_client_ctx *ctx);
+int nr_turn_client_deallocate(nr_turn_client_ctx *ctx);
+int nr_turn_client_send_indication(nr_turn_client_ctx *ctx,
+ const UCHAR *msg, size_t len,
+ int flags, const nr_transport_addr *remote_addr);
+int nr_turn_client_parse_data_indication(nr_turn_client_ctx *ctx,
+ nr_transport_addr *source_addr,
+ UCHAR *msg, size_t len,
+ UCHAR *newmsg, size_t *newlen,
+ size_t newsize,
+ nr_transport_addr *remote_addr);
+int nr_turn_client_ensure_perm(nr_turn_client_ctx *ctx,
+ const nr_transport_addr *addr);
+#endif
+