2012-10-03 00:04:58 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=2 et sw=2 tw=80: */
|
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
// Original author: ekr@rtfm.com
|
|
|
|
|
|
|
|
// Some of this code is cut-and-pasted from nICEr. Copyright is:
|
|
|
|
|
|
|
|
/*
|
|
|
|
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>
|
|
|
|
#include <vector>
|
|
|
|
|
2013-05-21 06:11:01 +04:00
|
|
|
#include "logging.h"
|
2012-10-03 00:04:58 +04:00
|
|
|
#include "nsError.h"
|
|
|
|
|
|
|
|
// nICEr includes
|
|
|
|
extern "C" {
|
|
|
|
#include "nr_api.h"
|
|
|
|
#include "registry.h"
|
|
|
|
#include "async_timer.h"
|
|
|
|
#include "ice_util.h"
|
|
|
|
#include "transport_addr.h"
|
|
|
|
#include "nr_crypto.h"
|
|
|
|
#include "nr_socket.h"
|
|
|
|
#include "nr_socket_local.h"
|
|
|
|
#include "stun_client_ctx.h"
|
|
|
|
#include "stun_server_ctx.h"
|
|
|
|
#include "ice_ctx.h"
|
|
|
|
#include "ice_candidate.h"
|
|
|
|
#include "ice_handler.h"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Local includes
|
|
|
|
#include "nricectx.h"
|
|
|
|
#include "nricemediastream.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2012-11-16 05:50:26 +04:00
|
|
|
MOZ_MTLOG_MODULE("mtransport")
|
2012-10-03 00:04:58 +04:00
|
|
|
|
2013-12-06 22:20:19 +04:00
|
|
|
static bool ToNrIceAddr(nr_transport_addr &addr,
|
|
|
|
NrIceAddr *out) {
|
|
|
|
int r;
|
|
|
|
char addrstring[INET6_ADDRSTRLEN + 1];
|
|
|
|
|
|
|
|
r = nr_transport_addr_get_addrstring(&addr, addrstring, sizeof(addrstring));
|
|
|
|
if (r)
|
|
|
|
return false;
|
|
|
|
out->host = addrstring;
|
|
|
|
|
|
|
|
int port;
|
|
|
|
r = nr_transport_addr_get_port(&addr, &port);
|
|
|
|
if (r)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
out->port = port;
|
|
|
|
|
|
|
|
switch (addr.protocol) {
|
|
|
|
case IPPROTO_TCP:
|
2017-02-04 01:48:02 +03:00
|
|
|
if (addr.tls_host[0] != '\0') {
|
|
|
|
out->transport = kNrIceTransportTls;
|
|
|
|
} else {
|
|
|
|
out->transport = kNrIceTransportTcp;
|
|
|
|
}
|
2013-12-06 22:20:19 +04:00
|
|
|
break;
|
|
|
|
case IPPROTO_UDP:
|
|
|
|
out->transport = kNrIceTransportUdp;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_CRASH();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-09 21:19:01 +04:00
|
|
|
static bool ToNrIceCandidate(const nr_ice_candidate& candc,
|
|
|
|
NrIceCandidate* out) {
|
|
|
|
MOZ_ASSERT(out);
|
2013-08-31 18:35:38 +04:00
|
|
|
int r;
|
|
|
|
// Const-cast because the internal nICEr code isn't const-correct.
|
|
|
|
nr_ice_candidate *cand = const_cast<nr_ice_candidate *>(&candc);
|
|
|
|
|
2013-12-06 22:20:19 +04:00
|
|
|
if (!ToNrIceAddr(cand->addr, &out->cand_addr))
|
2013-09-09 21:19:01 +04:00
|
|
|
return false;
|
2013-08-31 18:35:38 +04:00
|
|
|
|
2013-12-06 22:20:19 +04:00
|
|
|
if (cand->isock) {
|
|
|
|
nr_transport_addr addr;
|
|
|
|
r = nr_socket_getaddr(cand->isock->sock, &addr);
|
|
|
|
if (r)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!ToNrIceAddr(addr, &out->local_addr))
|
|
|
|
return false;
|
|
|
|
}
|
2013-08-31 18:35:38 +04:00
|
|
|
|
|
|
|
NrIceCandidate::Type type;
|
|
|
|
|
2013-09-09 21:19:01 +04:00
|
|
|
switch (cand->type) {
|
2013-08-31 18:35:38 +04:00
|
|
|
case HOST:
|
|
|
|
type = NrIceCandidate::ICE_HOST;
|
|
|
|
break;
|
|
|
|
case SERVER_REFLEXIVE:
|
|
|
|
type = NrIceCandidate::ICE_SERVER_REFLEXIVE;
|
|
|
|
break;
|
|
|
|
case PEER_REFLEXIVE:
|
|
|
|
type = NrIceCandidate::ICE_PEER_REFLEXIVE;
|
|
|
|
break;
|
|
|
|
case RELAYED:
|
|
|
|
type = NrIceCandidate::ICE_RELAYED;
|
|
|
|
break;
|
|
|
|
default:
|
2013-09-09 21:19:01 +04:00
|
|
|
return false;
|
2013-08-31 18:35:38 +04:00
|
|
|
}
|
|
|
|
|
2014-04-23 12:15:25 +04:00
|
|
|
NrIceCandidate::TcpType tcp_type;
|
|
|
|
switch (cand->tcp_type) {
|
|
|
|
case TCP_TYPE_ACTIVE:
|
|
|
|
tcp_type = NrIceCandidate::ICE_ACTIVE;
|
|
|
|
break;
|
|
|
|
case TCP_TYPE_PASSIVE:
|
|
|
|
tcp_type = NrIceCandidate::ICE_PASSIVE;
|
|
|
|
break;
|
|
|
|
case TCP_TYPE_SO:
|
|
|
|
tcp_type = NrIceCandidate::ICE_SO;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tcp_type = NrIceCandidate::ICE_NONE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-08-31 18:35:38 +04:00
|
|
|
out->type = type;
|
2014-04-23 12:15:25 +04:00
|
|
|
out->tcp_type = tcp_type;
|
2013-10-26 03:47:14 +04:00
|
|
|
out->codeword = candc.codeword;
|
2013-09-09 21:19:01 +04:00
|
|
|
return true;
|
|
|
|
}
|
2013-08-31 18:35:38 +04:00
|
|
|
|
2013-09-09 21:19:01 +04:00
|
|
|
// Make an NrIceCandidate from the candidate |cand|.
|
|
|
|
// This is not a member fxn because we want to hide the
|
|
|
|
// defn of nr_ice_candidate but we pass by reference.
|
2016-03-02 23:28:27 +03:00
|
|
|
static UniquePtr<NrIceCandidate> MakeNrIceCandidate(const nr_ice_candidate& candc) {
|
|
|
|
UniquePtr<NrIceCandidate> out(new NrIceCandidate());
|
2013-09-16 22:03:18 +04:00
|
|
|
|
2016-03-02 23:28:27 +03:00
|
|
|
if (!ToNrIceCandidate(candc, out.get())) {
|
2013-09-09 21:19:01 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
2016-03-02 23:28:27 +03:00
|
|
|
return out;
|
2013-08-31 18:35:38 +04:00
|
|
|
}
|
|
|
|
|
2012-10-03 00:04:58 +04:00
|
|
|
// NrIceMediaStream
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<NrIceMediaStream>
|
2012-10-03 00:04:58 +04:00
|
|
|
NrIceMediaStream::Create(NrIceCtx *ctx,
|
|
|
|
const std::string& name,
|
|
|
|
int components) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<NrIceMediaStream> stream =
|
2012-10-03 00:04:58 +04:00
|
|
|
new NrIceMediaStream(ctx, name, components);
|
2016-03-31 22:12:19 +03:00
|
|
|
MOZ_ASSERT(stream->ctx_ == ctx->ctx());
|
2012-10-03 00:04:58 +04:00
|
|
|
|
|
|
|
int r = nr_ice_add_media_stream(ctx->ctx(),
|
|
|
|
const_cast<char *>(name.c_str()),
|
|
|
|
components, &stream->stream_);
|
|
|
|
if (r) {
|
2013-07-03 22:40:36 +04:00
|
|
|
MOZ_MTLOG(ML_ERROR, "Couldn't create ICE media stream for '"
|
|
|
|
<< name << "'");
|
2012-10-03 00:04:58 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
2016-03-31 22:12:19 +03:00
|
|
|
NrIceMediaStream::NrIceMediaStream(NrIceCtx *ctx,
|
|
|
|
const std::string& name,
|
|
|
|
size_t components) :
|
|
|
|
state_(ICE_CONNECTING),
|
|
|
|
ctx_(ctx->ctx()),
|
|
|
|
ctx_peer_(ctx->peer()),
|
|
|
|
name_(name),
|
|
|
|
components_(components),
|
|
|
|
stream_(nullptr),
|
|
|
|
level_(0),
|
|
|
|
has_parsed_attrs_(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-10-03 00:04:58 +04:00
|
|
|
NrIceMediaStream::~NrIceMediaStream() {
|
|
|
|
// We do not need to destroy anything. All major resources
|
|
|
|
// are attached to the ice ctx.
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult NrIceMediaStream::ParseAttributes(std::vector<std::string>&
|
|
|
|
attributes) {
|
|
|
|
if (!stream_)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
std::vector<char *> attributes_in;
|
|
|
|
|
2017-02-13 16:42:00 +03:00
|
|
|
for (auto& attribute : attributes) {
|
|
|
|
attributes_in.push_back(const_cast<char *>(attribute.c_str()));
|
2012-10-03 00:04:58 +04:00
|
|
|
}
|
2012-09-26 21:14:23 +04:00
|
|
|
|
2012-10-03 00:04:58 +04:00
|
|
|
// Still need to call nr_ice_ctx_parse_stream_attributes.
|
2016-03-31 22:12:19 +03:00
|
|
|
int r = nr_ice_peer_ctx_parse_stream_attributes(ctx_peer_,
|
2012-10-03 00:04:58 +04:00
|
|
|
stream_,
|
2017-08-04 10:36:19 +03:00
|
|
|
attributes_in.empty() ?
|
|
|
|
nullptr : &attributes_in[0],
|
2012-10-03 00:04:58 +04:00
|
|
|
attributes_in.size());
|
|
|
|
if (r) {
|
2013-07-03 22:40:36 +04:00
|
|
|
MOZ_MTLOG(ML_ERROR, "Couldn't parse attributes for stream "
|
|
|
|
<< name_ << "'");
|
2012-10-03 00:04:58 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2014-12-11 02:53:54 +03:00
|
|
|
has_parsed_attrs_ = true;
|
2012-10-03 00:04:58 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse trickle ICE candidate
|
|
|
|
nsresult NrIceMediaStream::ParseTrickleCandidate(const std::string& candidate) {
|
|
|
|
int r;
|
|
|
|
|
2016-03-31 22:12:19 +03:00
|
|
|
MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << ctx_->label << ")/STREAM(" <<
|
2012-09-26 21:14:23 +04:00
|
|
|
name() << ") : parsing trickle candidate " << candidate);
|
2012-10-03 00:04:58 +04:00
|
|
|
|
2016-03-31 22:12:19 +03:00
|
|
|
r = nr_ice_peer_ctx_parse_trickle_candidate(ctx_peer_,
|
2013-01-20 03:18:28 +04:00
|
|
|
stream_,
|
|
|
|
const_cast<char *>(
|
|
|
|
candidate.c_str())
|
|
|
|
);
|
2012-10-03 00:04:58 +04:00
|
|
|
if (r) {
|
|
|
|
if (r == R_ALREADY) {
|
2013-07-03 22:40:36 +04:00
|
|
|
MOZ_MTLOG(ML_ERROR, "Trickle candidates are redundant for stream '"
|
|
|
|
<< name_ << "' because it is completed");
|
2012-10-03 00:04:58 +04:00
|
|
|
|
|
|
|
} else {
|
2013-07-03 22:40:36 +04:00
|
|
|
MOZ_MTLOG(ML_ERROR, "Couldn't parse trickle candidate for stream '"
|
|
|
|
<< name_ << "'");
|
2012-10-03 00:04:58 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-08-26 06:35:21 +04:00
|
|
|
// Returns NS_ERROR_NOT_AVAILABLE if component is unpaired or disabled.
|
2013-08-31 18:35:38 +04:00
|
|
|
nsresult NrIceMediaStream::GetActivePair(int component,
|
2016-03-02 23:28:27 +03:00
|
|
|
UniquePtr<NrIceCandidate>* localp,
|
|
|
|
UniquePtr<NrIceCandidate>* remotep) {
|
2013-08-31 18:35:38 +04:00
|
|
|
int r;
|
|
|
|
nr_ice_candidate *local_int;
|
|
|
|
nr_ice_candidate *remote_int;
|
|
|
|
|
2015-04-03 21:13:44 +03:00
|
|
|
if (!stream_) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
2016-03-31 22:12:19 +03:00
|
|
|
r = nr_ice_media_stream_get_active(ctx_peer_,
|
2013-08-31 18:35:38 +04:00
|
|
|
stream_,
|
|
|
|
component,
|
|
|
|
&local_int, &remote_int);
|
2013-08-26 06:35:21 +04:00
|
|
|
// If result is R_REJECTED then component is unpaired or disabled.
|
|
|
|
if (r == R_REJECTED)
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
|
2013-08-31 18:35:38 +04:00
|
|
|
if (r)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2016-03-02 23:28:27 +03:00
|
|
|
UniquePtr<NrIceCandidate> local(
|
2013-08-31 18:35:38 +04:00
|
|
|
MakeNrIceCandidate(*local_int));
|
|
|
|
if (!local)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2016-03-02 23:28:27 +03:00
|
|
|
UniquePtr<NrIceCandidate> remote(
|
2013-08-31 18:35:38 +04:00
|
|
|
MakeNrIceCandidate(*remote_int));
|
|
|
|
if (!remote)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
if (localp)
|
2016-03-02 23:28:27 +03:00
|
|
|
*localp = Move(local);
|
2013-08-31 18:35:38 +04:00
|
|
|
if (remotep)
|
2016-03-02 23:28:27 +03:00
|
|
|
*remotep = Move(remote);
|
2013-08-31 18:35:38 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-10-03 00:04:58 +04:00
|
|
|
|
2013-09-09 21:19:01 +04:00
|
|
|
nsresult NrIceMediaStream::GetCandidatePairs(std::vector<NrIceCandidatePair>*
|
2013-09-16 22:03:18 +04:00
|
|
|
out_pairs) const {
|
|
|
|
MOZ_ASSERT(out_pairs);
|
2015-04-03 21:13:44 +03:00
|
|
|
if (!stream_) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
2013-09-09 21:19:01 +04:00
|
|
|
|
2016-01-21 23:04:28 +03:00
|
|
|
// If we haven't at least started checking then there is nothing to report
|
2016-03-31 22:12:19 +03:00
|
|
|
if (ctx_peer_->state != NR_ICE_PEER_STATE_PAIRED) {
|
2016-01-21 23:04:28 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-09-09 21:19:01 +04:00
|
|
|
// Get the check_list on the peer stream (this is where the check_list
|
|
|
|
// actually lives, not in stream_)
|
2013-09-16 22:03:18 +04:00
|
|
|
nr_ice_media_stream* peer_stream;
|
2016-03-31 22:12:19 +03:00
|
|
|
int r = nr_ice_peer_ctx_find_pstream(ctx_peer_, stream_, &peer_stream);
|
2013-09-09 21:19:01 +04:00
|
|
|
if (r != 0) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2015-11-28 10:50:14 +03:00
|
|
|
nr_ice_cand_pair *p1, *p2;
|
2013-09-16 22:03:18 +04:00
|
|
|
out_pairs->clear();
|
2013-09-09 21:19:01 +04:00
|
|
|
|
2015-11-28 10:50:14 +03:00
|
|
|
TAILQ_FOREACH(p1, &peer_stream->check_list, check_queue_entry) {
|
2013-09-09 21:19:01 +04:00
|
|
|
MOZ_ASSERT(p1);
|
|
|
|
MOZ_ASSERT(p1->local);
|
|
|
|
MOZ_ASSERT(p1->remote);
|
|
|
|
NrIceCandidatePair pair;
|
|
|
|
|
2015-11-28 10:50:14 +03:00
|
|
|
p2 = TAILQ_FIRST(&peer_stream->check_list);
|
|
|
|
while (p2) {
|
|
|
|
if (p1 == p2) {
|
|
|
|
/* Don't compare with our self. */
|
|
|
|
p2=TAILQ_NEXT(p2, check_queue_entry);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (strncmp(p1->codeword,p2->codeword,sizeof(p1->codeword))==0) {
|
|
|
|
/* In case of duplicate pairs we only report the one winning pair */
|
|
|
|
if (
|
|
|
|
((p2->remote->component && (p2->remote->component->active == p2)) &&
|
|
|
|
!(p1->remote->component && (p1->remote->component->active == p1))) ||
|
|
|
|
((p2->peer_nominated || p2->nominated) &&
|
|
|
|
!(p1->peer_nominated || p1->nominated)) ||
|
|
|
|
(p2->priority > p1->priority) ||
|
|
|
|
((p2->state == NR_ICE_PAIR_STATE_SUCCEEDED) &&
|
2016-03-01 19:47:14 +03:00
|
|
|
(p1->state != NR_ICE_PAIR_STATE_SUCCEEDED)) ||
|
|
|
|
((p2->state != NR_ICE_PAIR_STATE_CANCELLED) &&
|
|
|
|
(p1->state == NR_ICE_PAIR_STATE_CANCELLED))
|
2015-11-28 10:50:14 +03:00
|
|
|
) {
|
|
|
|
/* p2 is a better pair. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p2=TAILQ_NEXT(p2, check_queue_entry);
|
|
|
|
}
|
|
|
|
if (p2) {
|
|
|
|
/* p2 points to a duplicate but better pair so skip this one */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-09-09 21:19:01 +04:00
|
|
|
switch (p1->state) {
|
|
|
|
case NR_ICE_PAIR_STATE_FROZEN:
|
|
|
|
pair.state = NrIceCandidatePair::State::STATE_FROZEN;
|
|
|
|
break;
|
|
|
|
case NR_ICE_PAIR_STATE_WAITING:
|
|
|
|
pair.state = NrIceCandidatePair::State::STATE_WAITING;
|
|
|
|
break;
|
|
|
|
case NR_ICE_PAIR_STATE_IN_PROGRESS:
|
|
|
|
pair.state = NrIceCandidatePair::State::STATE_IN_PROGRESS;
|
|
|
|
break;
|
|
|
|
case NR_ICE_PAIR_STATE_FAILED:
|
|
|
|
pair.state = NrIceCandidatePair::State::STATE_FAILED;
|
|
|
|
break;
|
|
|
|
case NR_ICE_PAIR_STATE_SUCCEEDED:
|
|
|
|
pair.state = NrIceCandidatePair::State::STATE_SUCCEEDED;
|
|
|
|
break;
|
|
|
|
case NR_ICE_PAIR_STATE_CANCELLED:
|
|
|
|
pair.state = NrIceCandidatePair::State::STATE_CANCELLED;
|
|
|
|
break;
|
|
|
|
default:
|
2013-09-16 22:03:18 +04:00
|
|
|
MOZ_ASSERT(0);
|
2013-09-09 21:19:01 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
pair.priority = p1->priority;
|
2013-09-16 22:03:18 +04:00
|
|
|
pair.nominated = p1->peer_nominated || p1->nominated;
|
2017-06-07 01:33:02 +03:00
|
|
|
// As discussed with drno: a component's can_send field (set to true
|
|
|
|
// by ICE consent) is a very close approximation for writable and
|
|
|
|
// readable. Note: the component for the local candidate never has
|
|
|
|
// the can_send member set to true, remote for both readable and
|
|
|
|
// writable. (mjf)
|
|
|
|
pair.writable = p1->remote->component->can_send;
|
|
|
|
pair.readable = p1->remote->component->can_send;
|
2013-11-09 04:45:39 +04:00
|
|
|
pair.selected = p1->remote->component &&
|
|
|
|
p1->remote->component->active == p1;
|
2013-10-24 22:45:10 +04:00
|
|
|
pair.codeword = p1->codeword;
|
2017-06-07 00:30:56 +03:00
|
|
|
pair.bytes_sent = p1->bytes_sent;
|
|
|
|
pair.bytes_recvd = p1->bytes_recvd;
|
2017-06-07 01:36:40 +03:00
|
|
|
pair.ms_since_last_send = p1->last_sent.tv_sec*1000
|
|
|
|
+ p1->last_sent.tv_usec/1000;
|
|
|
|
pair.ms_since_last_recv = p1->last_recvd.tv_sec*1000
|
|
|
|
+ p1->last_recvd.tv_usec/1000;
|
2013-09-09 21:19:01 +04:00
|
|
|
|
|
|
|
if (!ToNrIceCandidate(*(p1->local), &pair.local) ||
|
|
|
|
!ToNrIceCandidate(*(p1->remote), &pair.remote)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2013-09-16 22:03:18 +04:00
|
|
|
out_pairs->push_back(pair);
|
2013-09-09 21:19:01 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-11-20 03:16:29 +03:00
|
|
|
nsresult NrIceMediaStream::GetDefaultCandidate(
|
2015-05-09 01:52:41 +03:00
|
|
|
int component,
|
2014-11-20 03:16:29 +03:00
|
|
|
NrIceCandidate* candidate) const {
|
|
|
|
|
|
|
|
nr_ice_candidate *cand;
|
|
|
|
|
2015-05-09 01:52:41 +03:00
|
|
|
int r = nr_ice_media_stream_get_default_candidate(stream_, component, &cand);
|
2014-11-20 03:16:29 +03:00
|
|
|
if (r) {
|
|
|
|
MOZ_MTLOG(ML_ERROR, "Couldn't get default ICE candidate for '"
|
|
|
|
<< name_ << "'");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ToNrIceCandidate(*cand, candidate)) {
|
|
|
|
MOZ_MTLOG(ML_ERROR, "Failed to convert default ICE candidate for '"
|
|
|
|
<< name_ << "'");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-10-03 00:04:58 +04:00
|
|
|
std::vector<std::string> NrIceMediaStream::GetCandidates() const {
|
2017-06-28 22:38:00 +03:00
|
|
|
char **attrs = nullptr;
|
2012-10-03 00:04:58 +04:00
|
|
|
int attrct;
|
|
|
|
int r;
|
|
|
|
std::vector<std::string> ret;
|
|
|
|
|
2015-04-03 21:13:44 +03:00
|
|
|
if (!stream_) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-10-03 00:04:58 +04:00
|
|
|
r = nr_ice_media_stream_get_attributes(stream_,
|
|
|
|
&attrs, &attrct);
|
|
|
|
if (r) {
|
2013-07-03 22:40:36 +04:00
|
|
|
MOZ_MTLOG(ML_ERROR, "Couldn't get ICE candidates for '"
|
|
|
|
<< name_ << "'");
|
2012-10-03 00:04:58 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i=0; i<attrct; i++) {
|
|
|
|
ret.push_back(attrs[i]);
|
|
|
|
RFREE(attrs[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
RFREE(attrs);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-11-14 01:49:33 +04:00
|
|
|
static nsresult GetCandidatesFromStream(
|
|
|
|
nr_ice_media_stream *stream,
|
|
|
|
std::vector<NrIceCandidate> *candidates) {
|
|
|
|
MOZ_ASSERT(candidates);
|
|
|
|
nr_ice_component* comp=STAILQ_FIRST(&stream->components);
|
|
|
|
while(comp){
|
|
|
|
if (comp->state != NR_ICE_COMPONENT_DISABLED) {
|
|
|
|
nr_ice_candidate *cand = TAILQ_FIRST(&comp->candidates);
|
|
|
|
while(cand){
|
|
|
|
NrIceCandidate new_cand;
|
|
|
|
// This can fail if the candidate is server reflexive or relayed, and
|
|
|
|
// has not yet received a response (ie; it doesn't know its address
|
|
|
|
// yet). For the purposes of this code, this isn't a candidate we're
|
|
|
|
// interested in, since it is not fully baked yet.
|
|
|
|
if (ToNrIceCandidate(*cand, &new_cand)) {
|
|
|
|
candidates->push_back(new_cand);
|
|
|
|
}
|
|
|
|
cand=TAILQ_NEXT(cand,entry_comp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
comp=STAILQ_NEXT(comp,entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult NrIceMediaStream::GetLocalCandidates(
|
|
|
|
std::vector<NrIceCandidate>* candidates) const {
|
2015-04-03 21:13:44 +03:00
|
|
|
if (!stream_) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
2013-11-14 01:49:33 +04:00
|
|
|
return GetCandidatesFromStream(stream_, candidates);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult NrIceMediaStream::GetRemoteCandidates(
|
|
|
|
std::vector<NrIceCandidate>* candidates) const {
|
2015-04-03 21:13:44 +03:00
|
|
|
if (!stream_) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
2016-01-21 23:04:28 +03:00
|
|
|
// If we haven't at least started checking then there is nothing to report
|
2016-03-31 22:12:19 +03:00
|
|
|
if (ctx_peer_->state != NR_ICE_PEER_STATE_PAIRED) {
|
2016-01-21 23:04:28 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-11-14 01:49:33 +04:00
|
|
|
nr_ice_media_stream* peer_stream;
|
2016-03-31 22:12:19 +03:00
|
|
|
int r = nr_ice_peer_ctx_find_pstream(ctx_peer_, stream_, &peer_stream);
|
2013-11-14 01:49:33 +04:00
|
|
|
if (r != 0) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GetCandidatesFromStream(peer_stream, candidates);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-26 06:35:21 +04:00
|
|
|
nsresult NrIceMediaStream::DisableComponent(int component_id) {
|
|
|
|
if (!stream_)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
int r = nr_ice_media_stream_disable_component(stream_,
|
|
|
|
component_id);
|
|
|
|
if (r) {
|
|
|
|
MOZ_MTLOG(ML_ERROR, "Couldn't disable '" << name_ << "':" <<
|
|
|
|
component_id);
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-04-26 23:11:25 +03:00
|
|
|
nsresult NrIceMediaStream::GetConsentStatus(int component_id, bool *can_send, struct timeval *ts) {
|
|
|
|
if (!stream_)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nr_ice_media_stream* peer_stream;
|
|
|
|
int r = nr_ice_peer_ctx_find_pstream(ctx_peer_, stream_, &peer_stream);
|
|
|
|
if (r) {
|
|
|
|
MOZ_MTLOG(ML_ERROR, "Failed to find peer stream for '" << name_ << "':" <<
|
|
|
|
component_id);
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int send = 0;
|
|
|
|
r = nr_ice_media_stream_get_consent_status(peer_stream, component_id,
|
|
|
|
&send, ts);
|
|
|
|
if (r) {
|
|
|
|
MOZ_MTLOG(ML_ERROR, "Failed to get consent status for '" << name_ << "':" <<
|
|
|
|
component_id);
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
*can_send = !!send;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-10-03 00:04:58 +04:00
|
|
|
nsresult NrIceMediaStream::SendPacket(int component_id,
|
|
|
|
const unsigned char *data,
|
|
|
|
size_t len) {
|
|
|
|
if (!stream_)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2016-03-31 22:12:19 +03:00
|
|
|
int r = nr_ice_media_stream_send(ctx_peer_, stream_,
|
2012-10-03 00:04:58 +04:00
|
|
|
component_id,
|
|
|
|
const_cast<unsigned char *>(data), len);
|
|
|
|
if (r) {
|
2013-07-03 22:40:36 +04:00
|
|
|
MOZ_MTLOG(ML_ERROR, "Couldn't send media on '" << name_ << "'");
|
2012-10-03 00:04:58 +04:00
|
|
|
if (r == R_WOULDBLOCK) {
|
|
|
|
return NS_BASE_STREAM_WOULD_BLOCK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_BASE_STREAM_OSERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void NrIceMediaStream::Ready() {
|
2013-08-31 18:35:38 +04:00
|
|
|
// This function is called whenever a stream becomes ready, but it
|
|
|
|
// gets fired multiple times when a stream gets nominated repeatedly.
|
|
|
|
if (state_ != ICE_OPEN) {
|
|
|
|
MOZ_MTLOG(ML_DEBUG, "Marking stream ready '" << name_ << "'");
|
|
|
|
state_ = ICE_OPEN;
|
|
|
|
SignalReady(this);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
MOZ_MTLOG(ML_DEBUG, "Stream ready callback fired again for '" << name_ << "'");
|
|
|
|
}
|
2012-10-03 00:04:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void NrIceMediaStream::Close() {
|
2013-07-03 22:40:36 +04:00
|
|
|
MOZ_MTLOG(ML_DEBUG, "Marking stream closed '" << name_ << "'");
|
2012-10-03 00:04:58 +04:00
|
|
|
state_ = ICE_CLOSED;
|
2015-03-24 02:56:08 +03:00
|
|
|
|
2016-07-08 04:33:23 +03:00
|
|
|
if (stream_) {
|
|
|
|
int r = nr_ice_remove_media_stream(ctx_, &stream_);
|
|
|
|
if (r) {
|
|
|
|
MOZ_ASSERT(false, "Failed to remove stream");
|
|
|
|
MOZ_MTLOG(ML_ERROR, "Failed to remove stream, error=" << r);
|
|
|
|
}
|
2015-03-24 02:56:08 +03:00
|
|
|
}
|
2012-10-03 00:04:58 +04:00
|
|
|
}
|
2016-07-08 04:33:23 +03:00
|
|
|
|
2012-10-03 00:04:58 +04:00
|
|
|
} // close namespace
|