Esempio n. 1
0
void
PeerConnectionMedia::UpdateSinkIdentity_m(nsIPrincipal* aPrincipal,
                                          const PeerIdentity* aSinkIdentity)
{
  ASSERT_ON_THREAD(mMainThread);

  for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) {
    mLocalSourceStreams[u]->UpdateSinkIdentity_m(aPrincipal, aSinkIdentity);
  }
}
Esempio n. 2
0
int TestNrSocket::sendto(const void *msg, size_t len,
                         int flags, nr_transport_addr *to) {
  MOZ_ASSERT(my_addr_.protocol != IPPROTO_TCP);
  ASSERT_ON_THREAD(ststhread_);

  if (!nat_->enabled_ || nat_->is_an_internal_tuple(*to)) {
    return NrSocket::sendto(msg, len, flags, to);
  }

  destroy_stale_port_mappings();

  if (to->protocol == IPPROTO_UDP && nat_->block_udp_) {
    // Silently eat the packet
    return 0;
  }

  // Choose our port mapping based on our most selective criteria
  PortMapping *port_mapping = get_port_mapping(*to,
                                               std::max(nat_->filtering_type_,
                                                        nat_->mapping_type_));

  if (!port_mapping) {
    // See if we have already made the external socket we need to use.
    PortMapping *similar_port_mapping =
      get_port_mapping(*to, nat_->mapping_type_);
    nsRefPtr<NrSocket> external_socket;

    if (similar_port_mapping) {
      external_socket = similar_port_mapping->external_socket_;
    } else {
      external_socket = create_external_socket(*to);
      if (!external_socket) {
        MOZ_ASSERT(false);
        return R_INTERNAL;
      }
    }

    port_mapping = create_port_mapping(*to, external_socket);
    port_mappings_.push_back(port_mapping);

    if (poll_flags() & PR_POLL_READ) {
      // Make sure the new port mapping is ready to receive traffic if the
      // TestNrSocket is already waiting.
      port_mapping->async_wait(NR_ASYNC_WAIT_READ,
                              port_mapping_readable_callback,
                              this,
                              (char*)__FUNCTION__,
                              __LINE__);
    }
  }

  // We probably don't want to propagate the flags, since this is a simulated
  // external IP address.
  return port_mapping->sendto(msg, len, *to);
}
LocalSourceStreamInfo*
PeerConnectionMedia::GetLocalStreamByIndex(int aIndex)
{
  ASSERT_ON_THREAD(mMainThread);
  if(aIndex < 0 || aIndex >= (int) mLocalSourceStreams.Length()) {
    return nullptr;
  }

  MOZ_ASSERT(mLocalSourceStreams[aIndex]);
  return mLocalSourceStreams[aIndex];
}
void SourceStreamInfo::DetachMedia_m()
{
  ASSERT_ON_THREAD(mParent->GetMainThread());

  // walk through all the MediaPipelines and call the shutdown
  // media functions. Must be on the main thread.
  for (auto it = mPipelines.begin(); it != mPipelines.end(); ++it) {
    it->second->ShutdownMedia_m();
  }
  mMediaStream = nullptr;
}
Esempio n. 5
0
void
PeerConnectionMedia::UpdateSinkIdentity_m(const MediaStreamTrack* aTrack,
                                          nsIPrincipal* aPrincipal,
                                          const PeerIdentity* aSinkIdentity)
{
  ASSERT_ON_THREAD(mMainThread);

  for (RefPtr<TransceiverImpl>& transceiver : mTransceivers) {
    transceiver->UpdateSinkIdentity(aTrack, aPrincipal, aSinkIdentity);
  }
}
void
PeerConnectionMedia::PerformOrEnqueueIceCtxOperation(nsIRunnable* runnable)
{
  ASSERT_ON_THREAD(mMainThread);

  if (IsIceCtxReady()) {
    GetSTSThread()->Dispatch(runnable, NS_DISPATCH_NORMAL);
  } else {
    mQueuedIceCtxOperations.push_back(runnable);
  }
}
void RemoteSourceStreamInfo::DetachTransport_s()
{
  ASSERT_ON_THREAD(mParent->GetSTSThread());
  // walk through all the MediaPipelines and call the shutdown
  // transport functions. Must be on the STS thread.
  for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
           mPipelines.begin(); it != mPipelines.end();
       ++it) {
    it->second->ShutdownTransport_s();
  }
}
Esempio n. 8
0
void LocalSourceStreamInfo::DetachMedia_m()
{
  ASSERT_ON_THREAD(mParent->GetMainThread());
  // walk through all the MediaPipelines and call the shutdown
  // functions. Must be on the main thread.
  for (std::map<int, mozilla::RefPtr<mozilla::MediaPipeline> >::iterator it =
           mPipelines.begin(); it != mPipelines.end();
       ++it) {
    it->second->ShutdownMedia_m();
  }
}
// callback while UDP packet is sent
NS_IMETHODIMP NrSocketIpc::CallListenerSent(const nsACString &type,
                                            nsresult result) {
  ASSERT_ON_THREAD(main_thread_);
  MOZ_ASSERT(type.EqualsLiteral("onsent"));

  if (NS_FAILED(result)) {
    ReentrantMonitorAutoEnter mon(monitor_);
    err_ = true;
  }
  return NS_OK;
}
Esempio n. 10
0
int NrSocketIpc::getaddr(nr_transport_addr *addrp) {
  ASSERT_ON_THREAD(sts_thread_);

  ReentrantMonitorAutoEnter mon(monitor_);

  if (state_ != NR_CONNECTED) {
    return R_INTERNAL;
  }

  return nr_transport_addr_copy(addrp, &my_addr_);
}
Esempio n. 11
0
void
PeerConnectionMedia::GatherIfReady() {
  ASSERT_ON_THREAD(mMainThread);

  nsCOMPtr<nsIRunnable> runnable(WrapRunnable(
        RefPtr<PeerConnectionMedia>(this),
        &PeerConnectionMedia::EnsureIceGathering_s,
        GetPrefDefaultAddressOnly(),
        GetPrefProxyOnly()));

  PerformOrEnqueueIceCtxOperation(runnable);
}
Esempio n. 12
0
void
PeerConnectionMedia::FlushIceCtxOperationQueueIfReady()
{
  ASSERT_ON_THREAD(mMainThread);

  if (IsIceCtxReady()) {
    for (auto& mQueuedIceCtxOperation : mQueuedIceCtxOperations) {
      GetSTSThread()->Dispatch(mQueuedIceCtxOperation, NS_DISPATCH_NORMAL);
    }
    mQueuedIceCtxOperations.clear();
  }
}
Esempio n. 13
0
void
PeerConnectionMedia::SelfDestruct_m()
{
  CSFLogDebug(LOGTAG, "%s: ", __FUNCTION__);

  ASSERT_ON_THREAD(mMainThread);

  mMainThread = nullptr;

  // Final self-destruct.
  this->Release();
}
Esempio n. 14
0
int NrIceResolver::resolve(nr_resolver_resource *resource,
                           int (*cb)(void *cb_arg, nr_transport_addr *addr),
                           void *cb_arg,
                           void **handle) {
  int _status;
  MOZ_ASSERT(allocated_resolvers_ > 0);
  ASSERT_ON_THREAD(sts_thread_);
  RefPtr<PendingResolution> pr;
  uint32_t resolve_flags = 0;
  OriginAttributes attrs;

  if (resource->transport_protocol != IPPROTO_UDP &&
      resource->transport_protocol != IPPROTO_TCP) {
    MOZ_MTLOG(ML_ERROR, "Only UDP and TCP are supported.");
    ABORT(R_NOT_FOUND);
  }
  pr = new PendingResolution(sts_thread_,
                             resource->port? resource->port : 3478,
                             resource->transport_protocol ?
                             resource->transport_protocol :
                             IPPROTO_UDP,
                             cb, cb_arg);

  switch(resource->address_family) {
    case AF_INET:
      resolve_flags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
      break;
    case AF_INET6:
      resolve_flags |= nsIDNSService::RESOLVE_DISABLE_IPV4;
      break;
    default:
      ABORT(R_BAD_ARGS);
  }

  if (NS_FAILED(dns_->AsyncResolveNative(nsAutoCString(resource->domain_name),
                                         resolve_flags, pr,
                                         sts_thread_, attrs,
                                         getter_AddRefs(pr->request_)))) {
    MOZ_MTLOG(ML_ERROR, "AsyncResolve failed.");
    ABORT(R_NOT_FOUND);
  }
  // Because the C API offers no "finished" method to release the handle we
  // return, we cannot return the request we got from AsyncResolve directly.
  //
  // Instead, we return an addref'ed reference to PendingResolution itself,
  // which in turn holds the request and coordinates between cancel and
  // OnLookupComplete to release it only once.
  pr.forget(handle);

  _status=0;
abort:
  return _status;
}
void
PeerConnectionMedia::SelfDestruct_m()
{
  CSFLogDebug(logTag, "%s: ", __FUNCTION__);

  ASSERT_ON_THREAD(mMainThread);
  mLocalSourceStreams.Clear();
  mRemoteSourceStreams.Clear();

  // Final self-destruct.
  this->Release();
}
RemoteSourceStreamInfo*
PeerConnectionMedia::GetRemoteStreamByTrackId(const std::string& id)
{
  ASSERT_ON_THREAD(mMainThread);
  for (RefPtr<RemoteSourceStreamInfo>& info : mRemoteSourceStreams) {
    if (info->HasTrack(id)) {
      return info;
    }
  }

  return nullptr;
}
RemoteSourceStreamInfo*
PeerConnectionMedia::GetRemoteStreamById(const std::string& id)
{
  ASSERT_ON_THREAD(mMainThread);
  for (size_t i = 0; i < mRemoteSourceStreams.Length(); ++i) {
    if (id == mRemoteSourceStreams[i]->GetId()) {
      return mRemoteSourceStreams[i];
    }
  }

  return nullptr;
}
// callback for state update after every socket operation
NS_IMETHODIMP NrSocketIpc::UpdateReadyState(const nsACString &readyState) {
  ASSERT_ON_THREAD(main_thread_);

  ReentrantMonitorAutoEnter mon(monitor_);

  if (readyState.EqualsLiteral("closed")) {
    MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
    state_ = NR_CLOSED;
  }

  return NS_OK;
}
// This should be called on the STS thread.
int NrSocket::sendto(const void *msg, size_t len,
                     int flags, nr_transport_addr *to) {
  ASSERT_ON_THREAD(ststhread_);
  int r,_status;
  PRNetAddr naddr;
  int32_t status;

  if ((r=nr_transport_addr_to_praddr(to, &naddr)))
    ABORT(r);

  if(fd_==nullptr)
    ABORT(R_EOD);

  if (nr_is_stun_request_message((UCHAR*)msg, len)) {
    // Global rate limiting for stun requests, to mitigate the ice hammer DoS
    // (see http://tools.ietf.org/html/draft-thomson-mmusic-ice-webrtc)

    // Tolerate rate of 8k/sec, for one second.
    static SimpleTokenBucket burst(8192*1, 8192);
    // Tolerate rate of 3.6k/sec over twenty seconds.
    static SimpleTokenBucket sustained(3686*20, 3686);

    // Check number of tokens in each bucket.
    if (burst.getTokens(UINT32_MAX) < len ||
        sustained.getTokens(UINT32_MAX) < len) {
      r_log(LOG_GENERIC, LOG_ERR,
                 "Global rate limit for STUN requests exceeded.");
      MOZ_ASSERT("Global rate limit for STUN requests exceeded. Go bug "
                 "[email protected] if you weren't intentionally spamming "
                 "ICE candidates, or don't know what that means.");
      ABORT(R_WOULDBLOCK);
    }

    // Take len tokens from both buckets.
    // (not threadsafe, but no problem since this is only called from STS)
    burst.getTokens(len);
    sustained.getTokens(len);
  }

  // TODO: Convert flags?
  status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT);
  if (status < 0 || (size_t)status != len) {
    if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
      ABORT(R_WOULDBLOCK);

    r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s", to->as_string);
    ABORT(R_IO_ERROR);
  }

  _status=0;
abort:
  return(_status);
}
void
PeerConnectionMedia::BeginIceRestart_s(RefPtr<NrIceCtx> new_ctx)
{
  ASSERT_ON_THREAD(mSTSThread);

  // hold the original context so we can disconnect signals if needed
  RefPtr<NrIceCtx> originalCtx = mIceCtxHdlr->ctx();

  if (mIceCtxHdlr->BeginIceRestart(new_ctx)) {
    ConnectSignals(mIceCtxHdlr->ctx().get(), originalCtx.get());
  }
}
Esempio n. 21
0
// callback while UDP socket is opened
NS_IMETHODIMP NrSocketIpc::CallListenerOpened() {
  ASSERT_ON_THREAD(main_thread_);
  ReentrantMonitorAutoEnter mon(monitor_);

  uint16_t port;
  if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to get local port");
    return NS_OK;
  }

  nsAutoCString address;
  if(NS_FAILED(socket_child_->GetLocalAddress(address))) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to get local address");
    return NS_OK;
  }

  PRNetAddr praddr;
  if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
    return NS_OK;
  }

  if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
    return NS_OK;
  }

  nr_transport_addr expected_addr;
  if(nr_transport_addr_copy(&expected_addr, &my_addr_)) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to copy my_addr_");
  }

  if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
    err_ = true;
    MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
  }

  if (nr_transport_addr_cmp(&expected_addr, &my_addr_,
                            NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
    err_ = true;
    MOZ_ASSERT(false, "Address of opened socket is not expected");
  }

  mon.NotifyAll();

  return NS_OK;
}
Esempio n. 22
0
int TestNrSocket::recvfrom(void *buf, size_t maxlen,
                           size_t *len, int flags,
                           nr_transport_addr *from) {
  MOZ_ASSERT(my_addr_.protocol != IPPROTO_TCP);
  ASSERT_ON_THREAD(ststhread_);

  int r;
  bool ingress_allowed = false;

  if (readable_socket_) {
    // If any of the external sockets got data, see if it will be passed through
    r = readable_socket_->recvfrom(buf, maxlen, len, 0, from);
    readable_socket_ = nullptr;
    if (!r) {
      PortMapping *port_mapping_used;
      ingress_allowed = allow_ingress(*from, &port_mapping_used);
      if (ingress_allowed && nat_->refresh_on_ingress_ && port_mapping_used) {
        port_mapping_used->last_used_ = PR_IntervalNow();
      }
    }
  } else {
    // If no external socket has data, see if there's any data that was sent
    // directly to the TestNrSocket, and eat it if it isn't supposed to get
    // through.
    r = NrSocket::recvfrom(buf, maxlen, len, flags, from);
    if (!r) {
      // We do not use allow_ingress() here because that only handles traffic
      // landing on an external port.
      ingress_allowed = (!nat_->enabled_ ||
                         nat_->is_an_internal_tuple(*from));
      if (!ingress_allowed) {
        r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: "
                                     "Not behind the same NAT",
                                     my_addr_.as_string,
                                     from->as_string);
      }
    }
  }

  // Kinda lame that we are forced to give the app a readable callback and then
  // say "Oh, never mind...", but the alternative is to totally decouple the
  // callbacks from STS and the callbacks the app sets. On the bright side, this
  // speeds up unit tests where we are verifying that ingress is forbidden,
  // since they'll get a readable callback and then an error, instead of having
  // to wait for a timeout.
  if (!ingress_allowed) {
    *len = 0;
    r = R_WOULDBLOCK;
  }

  return r;
}
Esempio n. 23
0
nsresult
PeerConnectionMedia::AddRemoteStream(nsRefPtr<RemoteSourceStreamInfo> aInfo,
  int *aIndex)
{
  ASSERT_ON_THREAD(mMainThread);
  MOZ_ASSERT(aIndex);

  *aIndex = mRemoteSourceStreams.Length();

  mRemoteSourceStreams.AppendElement(aInfo);

  return NS_OK;
}
Esempio n. 24
0
void NrSocketIpc::sendto_m(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf) {
  ASSERT_ON_THREAD(main_thread_);

  MOZ_ASSERT(socket_child_);

  ReentrantMonitorAutoEnter mon(monitor_);

  if (NS_FAILED(socket_child_->SendWithAddress(&addr,
                                               buf->data(),
                                               buf->len()))) {
    err_ = true;
  }
}
Esempio n. 25
0
/**
 * Tells you if any local track is isolated to a specific peer identity.
 * Obviously, we want all the tracks to be isolated equally so that they can
 * all be sent or not.  We check once when we are setting a local description
 * and that determines if we flip the "privacy requested" bit on.  Once the bit
 * is on, all media originating from this peer connection is isolated.
 *
 * @returns true if any track has a peerIdentity set on it
 */
bool
PeerConnectionMedia::AnyLocalTrackHasPeerIdentity() const
{
  ASSERT_ON_THREAD(mMainThread);

  for (const RefPtr<TransceiverImpl>& transceiver : mTransceivers) {
    if (transceiver->GetSendTrack() &&
        transceiver->GetSendTrack()->GetPeerIdentity()) {
      return true;
    }
  }
  return false;
}
bool
PeerConnectionMedia::GetPrefDefaultAddressOnly() const
{
  ASSERT_ON_THREAD(mMainThread); // will crash on STS thread

#if !defined(MOZILLA_EXTERNAL_LINKAGE)
  bool default_address_only = Preferences::GetBool(
    "media.peerconnection.ice.default_address_only", false);
#else
  bool default_address_only = false;
#endif
  return default_address_only;
}
Esempio n. 27
0
bool
PeerConnectionMedia::GetPrefDefaultAddressOnly() const
{
  ASSERT_ON_THREAD(mMainThread); // will crash on STS thread

  uint64_t winId = mParent->GetWindow()->WindowID();

  bool default_address_only = Preferences::GetBool(
    "media.peerconnection.ice.default_address_only", false);
  default_address_only |=
    !MediaManager::Get()->IsActivelyCapturingOrHasAPermission(winId);
  return default_address_only;
}
Esempio n. 28
0
// IUDPSocketInternal interfaces
// callback while error happened in UDP socket operation
NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &message,
                                             const nsACString &filename,
                                             uint32_t line_number) {
  ASSERT_ON_THREAD(main_thread_);

  r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d",
        message.BeginReading(), filename.BeginReading(), line_number );

  ReentrantMonitorAutoEnter mon(monitor_);
  err_ = true;
  monitor_.NotifyAll();

  return NS_OK;
}
// nr_socket public APIs
int NrSocketIpc::create(nr_transport_addr *addr) {
  ASSERT_ON_THREAD(sts_thread_);

  int r, _status;
  nsresult rv;
  int32_t port;
  nsCString host;

  ReentrantMonitorAutoEnter mon(monitor_);

  if (state_ != NR_INIT) {
    ABORT(R_INTERNAL);
  }

  sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
  if (NS_FAILED(rv)) {
    MOZ_ASSERT(false, "Failed to get STS thread");
    ABORT(R_INTERNAL);
  }

  if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
    ABORT(r);
  }

  // wildcard address will be resolved at NrSocketIpc::CallListenerVoid
  if ((r=nr_transport_addr_copy(&my_addr_, addr))) {
    ABORT(r);
  }

  state_ = NR_CONNECTING;

  RUN_ON_THREAD(main_thread_,
                mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
                                      &NrSocketIpc::create_m,
                                      host, static_cast<uint16_t>(port)),
                NS_DISPATCH_NORMAL);

  // Wait until socket creation complete.
  mon.Wait();

  if (err_) {
    ABORT(R_INTERNAL);
  }

  state_ = NR_CONNECTED;

  _status = 0;
abort:
  return(_status);
}
/**
 * Tells you if any local track is isolated to a specific peer identity.
 * Obviously, we want all the tracks to be isolated equally so that they can
 * all be sent or not.  We check once when we are setting a local description
 * and that determines if we flip the "privacy requested" bit on.  Once the bit
 * is on, all media originating from this peer connection is isolated.
 *
 * @returns true if any track has a peerIdentity set on it
 */
bool
PeerConnectionMedia::AnyLocalTrackHasPeerIdentity() const
{
  ASSERT_ON_THREAD(mMainThread);

  for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) {
    for (auto pair : mLocalSourceStreams[u]->GetMediaStreamTracks()) {
      if (pair.second->GetPeerIdentity() != nullptr) {
        return true;
      }
    }
  }
  return false;
}