media/mtransport/nricemediastream.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 // Original author: ekr@rtfm.com
     9 // Some of this code is cut-and-pasted from nICEr. Copyright is:
    11 /*
    12 Copyright (c) 2007, Adobe Systems, Incorporated
    13 All rights reserved.
    15 Redistribution and use in source and binary forms, with or without
    16 modification, are permitted provided that the following conditions are
    17 met:
    19 * Redistributions of source code must retain the above copyright
    20   notice, this list of conditions and the following disclaimer.
    22 * Redistributions in binary form must reproduce the above copyright
    23   notice, this list of conditions and the following disclaimer in the
    24   documentation and/or other materials provided with the distribution.
    26 * Neither the name of Adobe Systems, Network Resonance nor the names of its
    27   contributors may be used to endorse or promote products derived from
    28   this software without specific prior written permission.
    30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    31 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    32 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    33 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    34 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    35 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    36 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    37 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    38 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    39 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    40 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    41 */
    44 #include <string>
    45 #include <vector>
    47 #include "logging.h"
    48 #include "nsError.h"
    49 #include "mozilla/Scoped.h"
    51 // nICEr includes
    52 extern "C" {
    53 #include "nr_api.h"
    54 #include "registry.h"
    55 #include "async_timer.h"
    56 #include "ice_util.h"
    57 #include "transport_addr.h"
    58 #include "nr_crypto.h"
    59 #include "nr_socket.h"
    60 #include "nr_socket_local.h"
    61 #include "stun_client_ctx.h"
    62 #include "stun_server_ctx.h"
    63 #include "ice_ctx.h"
    64 #include "ice_candidate.h"
    65 #include "ice_handler.h"
    66 }
    68 // Local includes
    69 #include "nricectx.h"
    70 #include "nricemediastream.h"
    72 namespace mozilla {
    74 MOZ_MTLOG_MODULE("mtransport")
    76 static bool ToNrIceAddr(nr_transport_addr &addr,
    77                         NrIceAddr *out) {
    78   int r;
    79   char addrstring[INET6_ADDRSTRLEN + 1];
    81   r = nr_transport_addr_get_addrstring(&addr, addrstring, sizeof(addrstring));
    82   if (r)
    83     return false;
    84   out->host = addrstring;
    86   int port;
    87   r = nr_transport_addr_get_port(&addr, &port);
    88   if (r)
    89     return false;
    91   out->port = port;
    93   switch (addr.protocol) {
    94     case IPPROTO_TCP:
    95       out->transport = kNrIceTransportTcp;
    96       break;
    97     case IPPROTO_UDP:
    98       out->transport = kNrIceTransportUdp;
    99       break;
   100     default:
   101       MOZ_CRASH();
   102       return false;
   103   }
   105   return true;
   106 }
   108 static bool ToNrIceCandidate(const nr_ice_candidate& candc,
   109                              NrIceCandidate* out) {
   110   MOZ_ASSERT(out);
   111   int r;
   112   // Const-cast because the internal nICEr code isn't const-correct.
   113   nr_ice_candidate *cand = const_cast<nr_ice_candidate *>(&candc);
   115   if (!ToNrIceAddr(cand->addr, &out->cand_addr))
   116     return false;
   118   if (cand->isock) {
   119     nr_transport_addr addr;
   120     r = nr_socket_getaddr(cand->isock->sock, &addr);
   121     if (r)
   122       return false;
   124     if (!ToNrIceAddr(addr, &out->local_addr))
   125       return false;
   126   }
   128   NrIceCandidate::Type type;
   130   switch (cand->type) {
   131     case HOST:
   132       type = NrIceCandidate::ICE_HOST;
   133       break;
   134     case SERVER_REFLEXIVE:
   135       type = NrIceCandidate::ICE_SERVER_REFLEXIVE;
   136       break;
   137     case PEER_REFLEXIVE:
   138       type = NrIceCandidate::ICE_PEER_REFLEXIVE;
   139       break;
   140     case RELAYED:
   141       type = NrIceCandidate::ICE_RELAYED;
   142       break;
   143     default:
   144       return false;
   145   }
   147   out->type = type;
   148   out->codeword = candc.codeword;
   149   return true;
   150 }
   152 // Make an NrIceCandidate from the candidate |cand|.
   153 // This is not a member fxn because we want to hide the
   154 // defn of nr_ice_candidate but we pass by reference.
   155 static NrIceCandidate* MakeNrIceCandidate(const nr_ice_candidate& candc) {
   156   ScopedDeletePtr<NrIceCandidate> out(new NrIceCandidate());
   158   if (!ToNrIceCandidate(candc, out)) {
   159     return nullptr;
   160   }
   161   return out.forget();
   162 }
   164 // NrIceMediaStream
   165 RefPtr<NrIceMediaStream>
   166 NrIceMediaStream::Create(NrIceCtx *ctx,
   167                          const std::string& name,
   168                          int components) {
   169   RefPtr<NrIceMediaStream> stream =
   170     new NrIceMediaStream(ctx, name, components);
   172   int r = nr_ice_add_media_stream(ctx->ctx(),
   173                                   const_cast<char *>(name.c_str()),
   174                                   components, &stream->stream_);
   175   if (r) {
   176     MOZ_MTLOG(ML_ERROR, "Couldn't create ICE media stream for '"
   177               << name << "'");
   178     return nullptr;
   179   }
   181   return stream;
   182 }
   184 NrIceMediaStream::~NrIceMediaStream() {
   185   // We do not need to destroy anything. All major resources
   186   // are attached to the ice ctx.
   187 }
   189 nsresult NrIceMediaStream::ParseAttributes(std::vector<std::string>&
   190                                            attributes) {
   191   if (!stream_)
   192     return NS_ERROR_FAILURE;
   194   std::vector<char *> attributes_in;
   196   for (size_t i=0; i<attributes.size(); ++i) {
   197     attributes_in.push_back(const_cast<char *>(attributes[i].c_str()));
   198   }
   200   // Still need to call nr_ice_ctx_parse_stream_attributes.
   201   int r = nr_ice_peer_ctx_parse_stream_attributes(ctx_->peer(),
   202                                                   stream_,
   203                                                   attributes_in.size() ?
   204                                                   &attributes_in[0] : nullptr,
   205                                                   attributes_in.size());
   206   if (r) {
   207     MOZ_MTLOG(ML_ERROR, "Couldn't parse attributes for stream "
   208               << name_ << "'");
   209     return NS_ERROR_FAILURE;
   210   }
   212   return NS_OK;
   213 }
   215 // Parse trickle ICE candidate
   216 nsresult NrIceMediaStream::ParseTrickleCandidate(const std::string& candidate) {
   217   int r;
   219   MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << ctx_->name() << ")/STREAM(" <<
   220             name() << ") : parsing trickle candidate " << candidate);
   222   r = nr_ice_peer_ctx_parse_trickle_candidate(ctx_->peer(),
   223                                               stream_,
   224                                               const_cast<char *>(
   225                                                 candidate.c_str())
   226                                               );
   227   if (r) {
   228     if (r == R_ALREADY) {
   229       MOZ_MTLOG(ML_ERROR, "Trickle candidates are redundant for stream '"
   230                 << name_ << "' because it is completed");
   232     } else {
   233       MOZ_MTLOG(ML_ERROR, "Couldn't parse trickle candidate for stream '"
   234                 << name_ << "'");
   235       return NS_ERROR_FAILURE;
   236     }
   237   }
   239   return NS_OK;
   240 }
   242 // Returns NS_ERROR_NOT_AVAILABLE if component is unpaired or disabled.
   243 nsresult NrIceMediaStream::GetActivePair(int component,
   244                                          NrIceCandidate **localp,
   245                                          NrIceCandidate **remotep) {
   246   int r;
   247   nr_ice_candidate *local_int;
   248   nr_ice_candidate *remote_int;
   250   r = nr_ice_media_stream_get_active(ctx_->peer(),
   251                                      stream_,
   252                                      component,
   253                                      &local_int, &remote_int);
   254   // If result is R_REJECTED then component is unpaired or disabled.
   255   if (r == R_REJECTED)
   256     return NS_ERROR_NOT_AVAILABLE;
   258   if (r)
   259     return NS_ERROR_FAILURE;
   261   ScopedDeletePtr<NrIceCandidate> local(
   262       MakeNrIceCandidate(*local_int));
   263   if (!local)
   264     return NS_ERROR_FAILURE;
   266   ScopedDeletePtr<NrIceCandidate> remote(
   267       MakeNrIceCandidate(*remote_int));
   268   if (!remote)
   269     return NS_ERROR_FAILURE;
   271   if (localp)
   272     *localp = local.forget();
   273   if (remotep)
   274     *remotep = remote.forget();
   276   return NS_OK;
   277 }
   280 nsresult NrIceMediaStream::GetCandidatePairs(std::vector<NrIceCandidatePair>*
   281                                              out_pairs) const {
   282   MOZ_ASSERT(out_pairs);
   284   // Get the check_list on the peer stream (this is where the check_list
   285   // actually lives, not in stream_)
   286   nr_ice_media_stream* peer_stream;
   287   int r = nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream);
   288   if (r != 0) {
   289     return NS_ERROR_FAILURE;
   290   }
   292   nr_ice_cand_pair *p1;
   293   out_pairs->clear();
   295   TAILQ_FOREACH(p1, &peer_stream->check_list, entry) {
   296     MOZ_ASSERT(p1);
   297     MOZ_ASSERT(p1->local);
   298     MOZ_ASSERT(p1->remote);
   299     NrIceCandidatePair pair;
   301     switch (p1->state) {
   302       case NR_ICE_PAIR_STATE_FROZEN:
   303         pair.state = NrIceCandidatePair::State::STATE_FROZEN;
   304         break;
   305       case NR_ICE_PAIR_STATE_WAITING:
   306         pair.state = NrIceCandidatePair::State::STATE_WAITING;
   307         break;
   308       case NR_ICE_PAIR_STATE_IN_PROGRESS:
   309         pair.state = NrIceCandidatePair::State::STATE_IN_PROGRESS;
   310         break;
   311       case NR_ICE_PAIR_STATE_FAILED:
   312         pair.state = NrIceCandidatePair::State::STATE_FAILED;
   313         break;
   314       case NR_ICE_PAIR_STATE_SUCCEEDED:
   315         pair.state = NrIceCandidatePair::State::STATE_SUCCEEDED;
   316         break;
   317       case NR_ICE_PAIR_STATE_CANCELLED:
   318         pair.state = NrIceCandidatePair::State::STATE_CANCELLED;
   319         break;
   320       default:
   321         MOZ_ASSERT(0);
   322     }
   324     pair.priority = p1->priority;
   325     pair.nominated = p1->peer_nominated || p1->nominated;
   326     pair.selected = p1->remote->component &&
   327                     p1->remote->component->active == p1;
   328     pair.codeword = p1->codeword;
   330     if (!ToNrIceCandidate(*(p1->local), &pair.local) ||
   331         !ToNrIceCandidate(*(p1->remote), &pair.remote)) {
   332       return NS_ERROR_FAILURE;
   333     }
   335     out_pairs->push_back(pair);
   336   }
   338   return NS_OK;
   339 }
   341 nsresult NrIceMediaStream::GetDefaultCandidate(int component,
   342                                                std::string *addrp,
   343                                                int *portp) {
   344   nr_ice_candidate *cand;
   345   int r;
   347   r = nr_ice_media_stream_get_default_candidate(stream_,
   348                                                 component, &cand);
   349   if (r) {
   350     if (ctx_->generating_trickle()) {
   351       // Generate default trickle candidates.
   352       // draft-ivov-mmusic-trickle-ice-01.txt says to use port 9
   353       // but "::" instead of "0.0.0.0". Since we don't do any
   354       // IPv6 we are ignoring that for now.
   355       *addrp = "0.0.0.0";
   356       *portp = 9;
   357     }
   358     else {
   359       MOZ_MTLOG(ML_ERROR, "Couldn't get default ICE candidate for '"
   360                 << name_ << "'");
   362       return NS_ERROR_NOT_AVAILABLE;
   363     }
   364   }
   365   else {
   366     char addr[64];  // Enough for IPv6 with colons.
   367     r = nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr));
   368     if (r)
   369       return NS_ERROR_FAILURE;
   371     int port;
   372     r=nr_transport_addr_get_port(&cand->addr,&port);
   373     if (r)
   374       return NS_ERROR_FAILURE;
   376     *addrp = addr;
   377     *portp = port;
   378   }
   380   return NS_OK;
   381 }
   383 std::vector<std::string> NrIceMediaStream::GetCandidates() const {
   384   char **attrs = 0;
   385   int attrct;
   386   int r;
   387   std::vector<std::string> ret;
   389   r = nr_ice_media_stream_get_attributes(stream_,
   390                                          &attrs, &attrct);
   391   if (r) {
   392     MOZ_MTLOG(ML_ERROR, "Couldn't get ICE candidates for '"
   393               << name_ << "'");
   394     return ret;
   395   }
   397   for (int i=0; i<attrct; i++) {
   398     ret.push_back(attrs[i]);
   399     RFREE(attrs[i]);
   400   }
   402   RFREE(attrs);
   404   return ret;
   405 }
   407 static nsresult GetCandidatesFromStream(
   408     nr_ice_media_stream *stream,
   409     std::vector<NrIceCandidate> *candidates) {
   410   MOZ_ASSERT(candidates);
   411   nr_ice_component* comp=STAILQ_FIRST(&stream->components);
   412   while(comp){
   413     if (comp->state != NR_ICE_COMPONENT_DISABLED) {
   414       nr_ice_candidate *cand = TAILQ_FIRST(&comp->candidates);
   415       while(cand){
   416         NrIceCandidate new_cand;
   417         // This can fail if the candidate is server reflexive or relayed, and
   418         // has not yet received a response (ie; it doesn't know its address
   419         // yet). For the purposes of this code, this isn't a candidate we're
   420         // interested in, since it is not fully baked yet.
   421         if (ToNrIceCandidate(*cand, &new_cand)) {
   422           candidates->push_back(new_cand);
   423         }
   424         cand=TAILQ_NEXT(cand,entry_comp);
   425       }
   426     }
   427     comp=STAILQ_NEXT(comp,entry);
   428   }
   430   return NS_OK;
   431 }
   433 nsresult NrIceMediaStream::GetLocalCandidates(
   434     std::vector<NrIceCandidate>* candidates) const {
   435   return GetCandidatesFromStream(stream_, candidates);
   436 }
   438 nsresult NrIceMediaStream::GetRemoteCandidates(
   439     std::vector<NrIceCandidate>* candidates) const {
   440   nr_ice_media_stream* peer_stream;
   441   int r = nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream);
   442   if (r != 0) {
   443     return NS_ERROR_FAILURE;
   444   }
   446   return GetCandidatesFromStream(peer_stream, candidates);
   447 }
   450 nsresult NrIceMediaStream::DisableComponent(int component_id) {
   451   if (!stream_)
   452     return NS_ERROR_FAILURE;
   454   int r = nr_ice_media_stream_disable_component(stream_,
   455                                                 component_id);
   456   if (r) {
   457     MOZ_MTLOG(ML_ERROR, "Couldn't disable '" << name_ << "':" <<
   458               component_id);
   459     return NS_ERROR_FAILURE;
   460   }
   462   return NS_OK;
   463 }
   465 nsresult NrIceMediaStream::SendPacket(int component_id,
   466                                       const unsigned char *data,
   467                                       size_t len) {
   468   if (!stream_)
   469     return NS_ERROR_FAILURE;
   471   int r = nr_ice_media_stream_send(ctx_->peer(), stream_,
   472                                    component_id,
   473                                    const_cast<unsigned char *>(data), len);
   474   if (r) {
   475     MOZ_MTLOG(ML_ERROR, "Couldn't send media on '" << name_ << "'");
   476     if (r == R_WOULDBLOCK) {
   477       return NS_BASE_STREAM_WOULD_BLOCK;
   478     }
   480     return NS_BASE_STREAM_OSERROR;
   481   }
   483   return NS_OK;
   484 }
   487 void NrIceMediaStream::Ready() {
   488   // This function is called whenever a stream becomes ready, but it
   489   // gets fired multiple times when a stream gets nominated repeatedly.
   490   if (state_ != ICE_OPEN) {
   491     MOZ_MTLOG(ML_DEBUG, "Marking stream ready '" << name_ << "'");
   492     state_ = ICE_OPEN;
   493     SignalReady(this);
   494   }
   495   else {
   496     MOZ_MTLOG(ML_DEBUG, "Stream ready callback fired again for '" << name_ << "'");
   497   }
   498 }
   500 void NrIceMediaStream::Close() {
   501   MOZ_MTLOG(ML_DEBUG, "Marking stream closed '" << name_ << "'");
   502   state_ = ICE_CLOSED;
   503   stream_ = nullptr;
   504 }
   505 }  // close namespace

mercurial