Bug 825708 - Part 2: calculate priority using properties. r=ekr
authorPatrick Wang <kk1fff@patrickz.net>
Wed, 28 Aug 2013 15:27:14 +0800
changeset 144857 ce48fdf481a8ff33a3bffea5c0a8a82cf98482b6
parent 144856 fddc6a6b32d8542c893f688e8735e3f7f8ef2b6a
child 144858 6c1b8dd0a787d19ecb60c60c00873100b3f7034d
push id25181
push useremorley@mozilla.com
push dateThu, 29 Aug 2013 13:44:51 +0000
treeherdermozilla-central@91672bee9a77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersekr
bugs825708
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 825708 - Part 2: calculate priority using properties. r=ekr
media/mtransport/nricectx.cpp
media/mtransport/nrinterfaceprioritizer.cpp
media/mtransport/nrinterfaceprioritizer.h
media/mtransport/objs.mk
media/mtransport/third_party/nICEr/nicer.gyp
media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
media/mtransport/third_party/nICEr/src/ice/ice_component.c
media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
media/mtransport/third_party/nICEr/src/net/nr_interface_prioritizer.c
media/mtransport/third_party/nICEr/src/net/nr_interface_prioritizer.h
media/mtransport/third_party/nICEr/src/net/transport_addr.c
media/mtransport/third_party/nICEr/src/net/transport_addr.h
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -77,16 +77,17 @@ extern "C" {
 #include "ice_candidate.h"
 #include "ice_handler.h"
 }
 
 // Local includes
 #include "nricectx.h"
 #include "nricemediastream.h"
 #include "nr_socket_prsock.h"
+#include "nrinterfaceprioritizer.h"
 
 namespace mozilla {
 
 MOZ_MTLOG_MODULE("mtransport")
 
 static bool initialized = false;
 
 // Implement NSPR-based crypto algorithms
@@ -363,16 +364,30 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const 
 
   r = nr_ice_ctx_create(const_cast<char *>(name.c_str()), flags,
                         &ctx->ctx_);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name << "'");
     return nullptr;
   }
 
+#ifdef USE_INTERFACE_PRIORITIZER
+  nr_interface_prioritizer *prioritizer = CreateInterfacePrioritizer();
+  if (!prioritizer) {
+    MOZ_MTLOG(PR_LOG_ERROR, "Couldn't create interface prioritizer.");
+    return nullptr;
+  }
+
+  r = nr_ice_ctx_set_interface_prioritizer(ctx->ctx_, prioritizer);
+  if (r) {
+    MOZ_MTLOG(PR_LOG_ERROR, "Couldn't set interface prioritizer.");
+    return nullptr;
+  }
+#endif  // USE_INTERFACE_PRIORITIZER
+
   // Create the handler objects
   ctx->ice_handler_vtbl_ = new nr_ice_handler_vtbl();
   ctx->ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair;
   ctx->ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready;
   ctx->ice_handler_vtbl_->stream_failed = &NrIceCtx::stream_failed;
   ctx->ice_handler_vtbl_->ice_completed = &NrIceCtx::ice_completed;
   ctx->ice_handler_vtbl_->msg_recvd = &NrIceCtx::msg_recvd;
 
new file mode 100644
--- /dev/null
+++ b/media/mtransport/nrinterfaceprioritizer.cpp
@@ -0,0 +1,189 @@
+/* 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/. */
+#include <map>
+#include <set>
+#include <string>
+#include "logging.h"
+#include "nrinterfaceprioritizer.h"
+#include "nsCOMPtr.h"
+
+MOZ_MTLOG_MODULE("mtransport")
+
+namespace {
+
+class LocalAddress {
+public:
+  LocalAddress()
+    : key_(),
+      is_vpn_(-1),
+      estimated_speed_(-1),
+      type_preference_(-1) {}
+
+  bool Init(const nr_local_addr& local_addr) {
+    char buf[MAXIFNAME + 41];
+    int r = nr_transport_addr_fmt_ifname_addr_string(&local_addr.addr, buf, sizeof(buf));
+    if (r) {
+      MOZ_MTLOG(PR_LOG_ERROR, "Error formatting interface address string.");
+      return false;
+    }
+    key_ = buf;
+    is_vpn_ = (local_addr.interface.type & NR_INTERFACE_TYPE_VPN) != 0 ? 1 : 0;
+    estimated_speed_ = local_addr.interface.estimated_speed;
+    type_preference_ = GetNetworkTypePreference(local_addr.interface.type);
+    return true;
+  }
+
+  bool operator<(const LocalAddress& rhs) const {
+    // Interface that is "less" here is preferred.
+    // If type preferences are different, we should simply sort by
+    // |type_preference_|.
+    if (type_preference_ != rhs.type_preference_) {
+      return type_preference_ < rhs.type_preference_;
+    }
+
+    // If type preferences are the same, the next thing we use to sort is vpn.
+    // If two LocalAddress are different in |is_vpn_|, the LocalAddress that is
+    // not in vpn gets priority.
+    if (is_vpn_ != rhs.is_vpn_) {
+      return is_vpn_ < rhs.is_vpn_;
+    }
+
+    // Compare estimated speed.
+    if (estimated_speed_ != rhs.estimated_speed_) {
+      return estimated_speed_ > rhs.estimated_speed_;
+    }
+
+    // All things above are the same, we can at least sort with key.
+    return key_ < rhs.key_;
+  }
+
+  const std::string& GetKey() const {
+    return key_;
+  }
+
+private:
+  // Getting the preference corresponding to a type. Getting lower number here
+  // means the type of network is preferred.
+  static inline int GetNetworkTypePreference(int type) {
+    if (type & NR_INTERFACE_TYPE_WIRED) {
+      return 1;
+    }
+    if (type & NR_INTERFACE_TYPE_WIFI) {
+      return 2;
+    }
+    if (type & NR_INTERFACE_TYPE_MOBILE) {
+      return 3;
+    }
+    return 4;
+  }
+
+  std::string key_;
+  int is_vpn_;
+  int estimated_speed_;
+  int type_preference_;
+};
+
+class InterfacePrioritizer {
+public:
+  InterfacePrioritizer()
+    : local_addrs_(),
+      preference_map_(),
+      sorted_(false) {}
+
+  int add(const nr_local_addr *iface) {
+    LocalAddress addr;
+    if (!addr.Init(*iface)) {
+      return R_FAILED;
+    }
+    std::pair<std::set<LocalAddress>::iterator, bool> r =
+      local_addrs_.insert(addr);
+    if (!r.second) {
+      return R_ALREADY; // This address is already in the set.
+    }
+    sorted_ = false;
+    return 0;
+  }
+
+  int sort() {
+    UCHAR tmp_pref = 127;
+    preference_map_.clear();
+    for (std::set<LocalAddress>::iterator i = local_addrs_.begin();
+         i != local_addrs_.end(); ++i) {
+      if (tmp_pref == 0) {
+        return R_FAILED;
+      }
+      preference_map_.insert(make_pair(i->GetKey(), tmp_pref--));
+    }
+    sorted_ = true;
+    return 0;
+  }
+
+  int getPreference(const char *key, UCHAR *pref) {
+    if (!sorted_) {
+      return R_FAILED;
+    }
+    std::map<std::string, UCHAR>::iterator i = preference_map_.find(key);
+    if (i == preference_map_.end()) {
+      return R_NOT_FOUND;
+    }
+    *pref = i->second;
+    return 0;
+  }
+
+private:
+  std::set<LocalAddress> local_addrs_;
+  std::map<std::string, UCHAR> preference_map_;
+  bool sorted_;
+};
+
+} // anonymous namespace
+
+static int add_interface(void *obj, nr_local_addr *iface) {
+  InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj);
+  return ip->add(iface);
+}
+
+static int get_priority(void *obj, const char *key, UCHAR *pref) {
+  InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj);
+  return ip->getPreference(key, pref);
+}
+
+static int sort_preference(void *obj) {
+  InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj);
+  return ip->sort();
+}
+
+static int destroy(void **objp) {
+  if (!objp || !*objp) {
+    return 0;
+  }
+
+  InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(*objp);
+  *objp = 0;
+  delete ip;
+
+  return 0;
+}
+
+static nr_interface_prioritizer_vtbl priorizer_vtbl = {
+  add_interface,
+  get_priority,
+  sort_preference,
+  destroy
+};
+
+namespace mozilla {
+
+nr_interface_prioritizer* CreateInterfacePrioritizer() {
+  nr_interface_prioritizer *ip;
+  int r = nr_interface_prioritizer_create_int(new InterfacePrioritizer(),
+                                              &priorizer_vtbl,
+                                              &ip);
+  if (r != 0) {
+    return nullptr;
+  }
+  return ip;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/media/mtransport/nrinterfaceprioritizer.h
@@ -0,0 +1,18 @@
+/* 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 nrinterfacepriority_h__
+#define nrinterfacepriority_h__
+
+extern "C" {
+#include "nr_api.h"
+#include "nr_interface_prioritizer.h"
+}
+
+namespace mozilla {
+
+nr_interface_prioritizer* CreateInterfacePrioritizer();
+
+} // namespace mozilla
+
+#endif
--- a/media/mtransport/objs.mk
+++ b/media/mtransport/objs.mk
@@ -35,17 +35,17 @@ DEFINES += -DBSD
 endif
 endif
 
 ifeq ($(OS_TARGET), Linux)
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/media/mtransport/third_party/nrappkit/src/port/linux/include \
   -I$(topsrcdir)/media/mtransport/third_party/nrappkit/src/port/generic/include \
   $(NULL)
-DEFINES += -DLINUX
+DEFINES += -DLINUX -DUSE_INTERFACE_PRIORITIZER
 endif
 
 ifeq ($(OS_TARGET), Android)
 LOCAL_INCLUDES += \
   -I$(topsrcdir)/media/mtransport/third_party/nrappkit/src/port/android/include \
   -I$(topsrcdir)/media/mtransport/third_party/nrappkit/src/port/generic/include \
   $(NULL)
 DEFINES += -DLINUX -DANDROID
@@ -66,27 +66,29 @@ DEFINES += \
    $(NULL)
 
 MTRANSPORT_LCPPSRCS = \
   dtlsidentity.cpp \
   nricectx.cpp \
   nricemediastream.cpp \
   nriceresolverfake.cpp \
   nriceresolver.cpp \
+  nrinterfaceprioritizer.cpp \
   nr_socket_prsock.cpp \
   nr_timer.cpp \
   transportflow.cpp \
   transportlayer.cpp \
   transportlayerice.cpp \
   transportlayerdtls.cpp \
   transportlayerlog.cpp \
   transportlayerloopback.cpp \
   transportlayerprsock.cpp \
   $(NULL)
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 MTRANSPORT_LCPPSRCS += \
   gonk_addrs.cpp \
   $(NULL)
+DEFINES += -DUSE_INTERFACE_PRIORITIZER
 endif
 
 MTRANSPORT_CPPSRCS = $(addprefix $(topsrcdir)/media/mtransport/, $(MTRANSPORT_LCPPSRCS))
 
--- a/media/mtransport/third_party/nICEr/nicer.gyp
+++ b/media/mtransport/third_party/nICEr/nicer.gyp
@@ -73,16 +73,18 @@
                 #"./src/net/nr_socket_local.c",
                 "./src/net/nr_socket_local.h",
                 "./src/net/transport_addr.c",
                 "./src/net/transport_addr.h",
                 "./src/net/transport_addr_reg.c",
                 "./src/net/transport_addr_reg.h",
                 "./src/net/local_addr.c",
                 "./src/net/local_addr.h",
+                "./src/net/nr_interface_prioritizer.c",
+                "./src/net/nr_interface_prioritizer.h",
 
                 # STUN
                 "./src/stun/addrs.c",
                 "./src/stun/addrs.h",
                 "./src/stun/nr_socket_turn.c",
                 "./src/stun/nr_socket_turn.h",
                 "./src/stun/stun.h",
                 "./src/stun/stun_build.c",
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -353,33 +353,47 @@ int nr_ice_candidate_compute_priority(nr
         break;
       default:
         ABORT(R_INTERNAL);
     }
 
     if(type_preference > 126)
       r_log(LOG_ICE,LOG_ERR,"Illegal type preference %d",type_preference);
 
-
-    if(r=NR_reg_get2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,
-      &interface_preference)) {
-      if (r==R_NOT_FOUND) {
-        if (next_automatic_preference == 1) {
-          r_log(LOG_ICE,LOG_DEBUG,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
-          ABORT(R_NOT_FOUND);
+    if(!cand->ctx->interface_prioritizer) {
+      /* Prioritizer is not set, read from registry */
+      if(r=NR_reg_get2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,
+        &interface_preference)) {
+        if (r==R_NOT_FOUND) {
+          if (next_automatic_preference == 1) {
+            r_log(LOG_ICE,LOG_DEBUG,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
+            ABORT(R_NOT_FOUND);
+          }
+          r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
+            next_automatic_preference);
+          if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
+            ABORT(r);
+          }
+          interface_preference=next_automatic_preference;
+          next_automatic_preference--;
         }
-        r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
-          next_automatic_preference);
-        if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
+        else {
           ABORT(r);
         }
-        interface_preference=next_automatic_preference;
-        next_automatic_preference--;
       }
-      else {
+    }
+    else {
+      char key_of_interface[MAXIFNAME + 41];
+
+      if(r=nr_transport_addr_fmt_ifname_addr_string(&cand->base,key_of_interface,
+         sizeof(key_of_interface))) {
+        ABORT(r);
+      }
+      if(r=nr_interface_prioritizer_get_priority(cand->ctx->interface_prioritizer,
+         key_of_interface,&interface_preference)) {
         ABORT(r);
       }
     }
 
     cand->priority=
       (type_preference << 24) |
       (interface_preference << 16) |
       (stun_priority << 8) |
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c
@@ -165,41 +165,34 @@ int nr_ice_component_destroy(nr_ice_comp
     if(component->keepalive_timer)
       NR_async_timer_cancel(component->keepalive_timer);
     nr_stun_client_ctx_destroy(&component->keepalive_ctx);
 
     RFREE(component);
     return(0);
   }
 
-#define MAXADDRS 100 // Ridiculously high
 /* Make all the candidates we can make at the beginning */
 int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *component)
   {
     int r,_status;
-    nr_local_addr addrs[MAXADDRS];
+    nr_local_addr *addrs=ctx->local_addrs;
     nr_socket *sock;
     nr_ice_socket *isock=0;
     nr_ice_candidate *cand=0;
     char *lufrag;
     char *lpwd;
     Data pwd;
-    int addr_ct;
+    int addr_ct=ctx->local_addr_ct;
     int i;
     int j;
     char label[256];
 
     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): initializing component with id %d",ctx->label,component->component_id);
 
-    /* First, gather all the local addresses we have */
-    if(r=nr_stun_find_local_addresses(addrs,MAXADDRS,&addr_ct)) {
-      r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to find local addresses",ctx->label);
-      ABORT(r);
-    }
-
     if(addr_ct==0){
       r_log(LOG_ICE,LOG_ERR,"ICE(%s): no local addresses available",ctx->label);
       ABORT(R_NOT_FOUND);
     }
 
     /* Now one ice_socket for each address */
     for(i=0;i<addr_ct;i++){
       char suppress;
--- a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.c
@@ -151,31 +151,72 @@ int nr_ice_ctx_set_turn_servers(nr_ice_c
       ctx->turn_server_ct = ct;
     }
 
     _status=0;
  abort:
     return(_status);
   }
 
+int nr_ice_ctx_set_local_addrs(nr_ice_ctx *ctx,nr_local_addr *addrs,int ct)
+  {
+    int _status,i,r;
+
+    if(ctx->local_addrs) {
+      RFREE(ctx->local_addrs);
+      ctx->local_addr_ct=0;
+      ctx->local_addrs=0;
+    }
+
+    if (ct) {
+      if(!(ctx->local_addrs=RCALLOC(sizeof(nr_local_addr)*ct)))
+        ABORT(R_NO_MEMORY);
+
+      for (i=0;i<ct;++i) {
+        if (r=nr_local_addr_copy(ctx->local_addrs+i,addrs+i)) {
+          ABORT(r);
+        }
+      }
+      ctx->local_addr_ct = ct;
+    }
+
+    _status=0;
+   abort:
+    return(_status);
+  }
+
 int nr_ice_ctx_set_resolver(nr_ice_ctx *ctx, nr_resolver *resolver)
   {
     int _status;
 
     if (ctx->resolver) {
       ABORT(R_ALREADY);
     }
 
     ctx->resolver = resolver;
 
     _status=0;
    abort:
     return(_status);
   }
 
+int nr_ice_ctx_set_interface_prioritizer(nr_ice_ctx *ctx, nr_interface_prioritizer *ip)
+  {
+    int _status;
+
+    if (ctx->interface_prioritizer) {
+      ABORT(R_ALREADY);
+    }
+
+    ctx->interface_prioritizer = ip;
+
+    _status=0;
+   abort:
+    return(_status);
+  }
 
 #ifdef USE_TURN
 int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out)
   {
     int r,_status;
     nr_ice_turn_server *servers = 0;
     int i;
     NR_registry child;
@@ -296,16 +337,19 @@ int nr_ice_ctx_create(char *label, UINT4
       (unsigned int *)&ctx->turn_server_ct)||ctx->turn_server_ct==0) {
       r_log(LOG_ICE,LOG_NOTICE,"No TURN servers specified");
       ctx->turn_server_ct=0;
     }
 #else
     ctx->turn_server_ct=0;
 #endif /* USE_TURN */
 
+    ctx->local_addrs=0;
+    ctx->local_addr_ct=0;
+
     /* 255 is the max for our priority algorithm */
     if((ctx->stun_server_ct+ctx->turn_server_ct)>255){
       r_log(LOG_ICE,LOG_WARNING,"Too many STUN/TURN servers specified: max=255");
       ctx->turn_server_ct=255-ctx->stun_server_ct;
     }
 
 #ifdef USE_TURN
     if(ctx->turn_server_ct>0){
@@ -343,16 +387,18 @@ static void nr_ice_ctx_destroy_cb(NR_SOC
     nr_ice_media_stream *s1,*s2;
     int i;
     nr_ice_stun_id *id1,*id2;
 
     RFREE(ctx->label);
 
     RFREE(ctx->stun_servers);
 
+    RFREE(ctx->local_addrs);
+
     for (i = 0; i < ctx->turn_server_ct; i++) {
         RFREE(ctx->turn_servers[i].username);
         r_data_destroy(&ctx->turn_servers[i].password);
     }
     RFREE(ctx->turn_servers);
 
     f1=STAILQ_FIRST(&ctx->foundations);
     while(f1){
@@ -369,16 +415,17 @@ static void nr_ice_ctx_destroy_cb(NR_SOC
     }
 
     STAILQ_FOREACH_SAFE(id1, &ctx->ids, entry, id2){
       STAILQ_REMOVE(&ctx->ids,id1,nr_ice_stun_id_,entry);
       RFREE(id1);
     }
 
     nr_resolver_destroy(&ctx->resolver);
+    nr_interface_prioritizer_destroy(&ctx->interface_prioritizer);
 
     RFREE(ctx);
   }
 
 int nr_ice_ctx_destroy(nr_ice_ctx **ctxp)
   {
     if(!ctxp || !*ctxp)
       return(0);
@@ -411,31 +458,58 @@ void nr_ice_initialize_finished_cb(NR_SO
         r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): No done_cb. We were probably destroyed.",ctx->label);
       }
     }
     else {
       r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Waiting for %d candidates to be initialized",ctx->label, ctx->uninitialized_candidates);
     }
   }
 
+#define MAXADDRS 100 // Ridiculously high
 int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg)
   {
     int r,_status;
     nr_ice_media_stream *stream;
+    nr_local_addr addrs[MAXADDRS];
+    int i,addr_ct;
 
     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Initializing candidates",ctx->label);
     ctx->state=NR_ICE_STATE_INITIALIZING;
     ctx->done_cb=done_cb;
     ctx->cb_arg=cb_arg;
 
     if(STAILQ_EMPTY(&ctx->streams)) {
       r_log(LOG_ICE,LOG_ERR,"ICE(%s): Missing streams to initialize",ctx->label);
       ABORT(R_BAD_ARGS);
     }
 
+    /* First, gather all the local addresses we have */
+    if(r=nr_stun_find_local_addresses(addrs,MAXADDRS,&addr_ct)) {
+      r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to find local addresses",ctx->label);
+      ABORT(r);
+    }
+
+    /* Sort interfaces by preference */
+    if(ctx->interface_prioritizer) {
+      for(i=0;i<addr_ct;i++){
+        if(r=nr_interface_prioritizer_add_interface(ctx->interface_prioritizer,addrs+i)) {
+          r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to add interface ",ctx->label);
+          ABORT(r);
+        }
+      }
+      if(r=nr_interface_prioritizer_sort_preference(ctx->interface_prioritizer)) {
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to sort interface by preference",ctx->label);
+        ABORT(r);
+      }
+    }
+
+    if (r=nr_ice_ctx_set_local_addrs(ctx,addrs,addr_ct)) {
+      ABORT(r);
+    }
+
     /* Initialize all the media stream/component pairs */
     stream=STAILQ_FIRST(&ctx->streams);
     while(stream){
       if(r=nr_ice_media_stream_initialize(ctx,stream))
         ABORT(r);
 
       stream=STAILQ_NEXT(stream,entry);
     }
--- a/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_ctx.h
@@ -38,16 +38,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 using namespace std;
 extern "C" {
 #endif /* __cplusplus */
 
 /* Not good practice but making includes simpler */
 #include "transport_addr.h"
 #include "nr_socket.h"
 #include "nr_resolver.h"
+#include "nr_interface_prioritizer.h"
 #include "stun_client_ctx.h"
 #include "stun_server_ctx.h"
 #include "turn_client_ctx.h"
 
 #define NR_ICE_STUN_SERVER_TYPE_ADDR    1
 #define NR_ICE_STUN_SERVER_TYPE_DNSNAME 2
 
 typedef struct nr_ice_stun_server_ {
@@ -117,18 +118,21 @@ struct nr_ice_ctx_ {
   char *pwd;
 
   UINT4 Ta;
 
   nr_ice_stun_server *stun_servers;           /* The list of stun servers */
   int stun_server_ct;
   nr_ice_turn_server *turn_servers;           /* The list of turn servers */
   int turn_server_ct;
+  nr_local_addr *local_addrs;                 /* The list of available local addresses and corresponding interface information */
+  int local_addr_ct;
 
   nr_resolver *resolver;                      /* The resolver to use */
+  nr_interface_prioritizer *interface_prioritizer;  /* Priority decision logic */
 
   nr_ice_foundation_head foundations;
 
   nr_ice_media_stream_head streams;           /* Media streams */
   int stream_ct;
   nr_ice_socket_head sockets;                 /* The sockets we're using */
   int uninitialized_candidates;
 
@@ -156,16 +160,17 @@ int nr_ice_add_media_stream(nr_ice_ctx *
 int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp);
 int nr_ice_ctx_deliver_packet(nr_ice_ctx *ctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len);
 int nr_ice_ctx_is_known_id(nr_ice_ctx *ctx, UCHAR id[12]);
 int nr_ice_ctx_remember_id(nr_ice_ctx *ctx, nr_stun_message *msg);
 int nr_ice_ctx_finalize(nr_ice_ctx *ctx, nr_ice_peer_ctx *pctx);
 int nr_ice_ctx_set_stun_servers(nr_ice_ctx *ctx,nr_ice_stun_server *servers, int ct);
 int nr_ice_ctx_set_turn_servers(nr_ice_ctx *ctx,nr_ice_turn_server *servers, int ct);
 int nr_ice_ctx_set_resolver(nr_ice_ctx *ctx, nr_resolver *resolver);
+int nr_ice_ctx_set_interface_prioritizer(nr_ice_ctx *ctx, nr_interface_prioritizer *prioritizer);
 
 extern int LOG_ICE;
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 #endif
 
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/net/nr_interface_prioritizer.c
@@ -0,0 +1,88 @@
+/*
+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.
+*/
+
+#include "nr_api.h"
+#include "nr_interface_prioritizer.h"
+#include "transport_addr.h"
+
+int nr_interface_prioritizer_create_int(void *obj,
+  nr_interface_prioritizer_vtbl *vtbl,nr_interface_prioritizer **ifpp)
+  {
+    int _status;
+    nr_interface_prioritizer *ifp=0;
+
+    if(!(ifp=RCALLOC(sizeof(nr_interface_prioritizer))))
+      ABORT(R_NO_MEMORY);
+
+    ifp->obj = obj;
+    ifp->vtbl = vtbl;
+
+    *ifpp = ifp;
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_interface_prioritizer_destroy(nr_interface_prioritizer **ifpp)
+  {
+    nr_interface_prioritizer *ifp;
+
+    if (!ifpp || !*ifpp)
+      return(0);
+
+    ifp = *ifpp;
+    *ifpp = 0;
+    ifp->vtbl->destroy(&ifp->obj);
+    RFREE(ifp);
+    return(0);
+  }
+
+int nr_interface_prioritizer_add_interface(nr_interface_prioritizer *ifp,
+  nr_local_addr *addr)
+  {
+    return ifp->vtbl->add_interface(ifp->obj, addr);
+  }
+
+int nr_interface_prioritizer_get_priority(nr_interface_prioritizer *ifp,
+  const char *key, UCHAR *interface_preference)
+  {
+    return ifp->vtbl->get_priority(ifp->obj,key,interface_preference);
+  }
+
+int nr_interface_prioritizer_sort_preference(nr_interface_prioritizer *ifp)
+  {
+    return ifp->vtbl->sort_preference(ifp->obj);
+  }
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/net/nr_interface_prioritizer.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, 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 _nr_interface_prioritizer
+#define _nr_interface_prioritizer
+
+#include "transport_addr.h"
+#include "local_addr.h"
+
+typedef struct nr_interface_prioritizer_vtbl_ {
+  int (*add_interface)(void *obj, nr_local_addr *iface);
+  int (*get_priority)(void *obj, const char *key, UCHAR *pref);
+  int (*sort_preference)(void *obj);
+  int (*destroy)(void **obj);
+} nr_interface_prioritizer_vtbl;
+
+typedef struct nr_interface_prioritizer_ {
+  void *obj;
+  nr_interface_prioritizer_vtbl *vtbl;
+} nr_interface_prioritizer;
+
+int nr_interface_prioritizer_create_int(void *obj, nr_interface_prioritizer_vtbl *vtbl,
+                                        nr_interface_prioritizer **prioritizer);
+
+int nr_interface_prioritizer_destroy(nr_interface_prioritizer **prioritizer);
+
+int nr_interface_prioritizer_add_interface(nr_interface_prioritizer *prioritizer,
+                                           nr_local_addr *addr);
+
+int nr_interface_prioritizer_get_priority(nr_interface_prioritizer *prioritizer,
+                                          const char *key, UCHAR *interface_preference);
+
+int nr_interface_prioritizer_sort_preference(nr_interface_prioritizer *prioritizer);
+#endif
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.c
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.c
@@ -73,16 +73,37 @@ int nr_transport_addr_fmt_addr_string(nr
         ABORT(R_INTERNAL);
     }
 
     _status=0;
   abort:
     return(_status);
   }
 
+int nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr *addr, char *buf, int len)
+  {
+    int _status;
+    char buffer[40];
+
+    switch(addr->ip_version){
+      case NR_IPV4:
+        if (!inet_ntop(AF_INET, &addr->u.addr4.sin_addr,buffer,sizeof(buffer))) {
+           strncpy(buffer, "[error]", len);
+        }
+        snprintf(buf,len,"%s:%s",addr->ifname,buffer);
+        break;
+      default:
+        ABORT(R_INTERNAL);
+    }
+
+    _status=0;
+  abort:
+    return(_status);
+  }
+
 int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr)
   {
     int r,_status;
 
     if(!keep) memset(addr,0,sizeof(nr_transport_addr));
 
     if(saddr->sa_family==PF_INET){
       if(saddr_len != sizeof(struct sockaddr_in))
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.h
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.h
@@ -86,12 +86,13 @@ int nr_transport_addr_cmp(nr_transport_a
 #define NR_TRANSPORT_ADDR_CMP_MODE_ADDR      3
 #define NR_TRANSPORT_ADDR_CMP_MODE_ALL       4
 
 int nr_transport_addr_is_wildcard(nr_transport_addr *addr);
 int nr_transport_addr_is_loopback(nr_transport_addr *addr);
 int nr_transport_addr_copy(nr_transport_addr *to, nr_transport_addr *from);
 int nr_transport_addr_copy_keep_ifname(nr_transport_addr *to, nr_transport_addr *from);
 int nr_transport_addr_fmt_addr_string(nr_transport_addr *addr);
+int nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr *addr, char *buf, int len);
 int nr_transport_addr_set_port(nr_transport_addr *addr, int port);
 
 #endif