Bug 891551 - Part 5: Add support for TCP ICE candidates. r=bwc,jesup

This commit is contained in:
"Peter Tatrai ext:(%22) 2014-04-23 10:15:25 +02:00
parent aec584b5a8
commit 6d354a80da
36 changed files with 2213 additions and 272 deletions

View File

@ -276,14 +276,14 @@ NS_IMPL_ISUPPORTS0(NrSocket)
// The nsASocket callbacks
void NrSocket::OnSocketReady(PRFileDesc *fd, int16_t outflags) {
if (outflags & PR_POLL_READ)
if (outflags & PR_POLL_READ & poll_flags())
fire_callback(NR_ASYNC_WAIT_READ);
if (outflags & PR_POLL_WRITE)
if (outflags & PR_POLL_WRITE & poll_flags())
fire_callback(NR_ASYNC_WAIT_WRITE);
}
void NrSocket::OnSocketDetached(PRFileDesc *fd) {
; // TODO: Log?
r_log(LOG_GENERIC, LOG_DEBUG, "Socket %p detached", fd);
}
void NrSocket::IsLocal(bool *aIsLocal) {
@ -526,6 +526,27 @@ int NrSocket::create(nr_transport_addr *addr) {
r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
ABORT(R_INTERNAL);
}
// Set ReuseAddr for TCP sockets to enable having several
// sockets bound to same local IP and port
PRSocketOptionData opt_reuseaddr;
opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
opt_reuseaddr.value.reuse_addr = PR_TRUE;
status = PR_SetSocketOption(fd_, &opt_reuseaddr);
if (status != PR_SUCCESS) {
r_log(LOG_GENERIC, LOG_CRIT, "Couldn't set reuse addr socket option");
ABORT(R_INTERNAL);
}
// And also set ReusePort for platforms supporting this socket option
PRSocketOptionData opt_reuseport;
opt_reuseport.option = PR_SockOpt_Reuseport;
opt_reuseport.value.reuse_port = PR_TRUE;
status = PR_SetSocketOption(fd_, &opt_reuseport);
if (status != PR_SUCCESS) {
if (PR_GetError() != PR_OPERATION_NOT_SUPPORTED_ERROR) {
r_log(LOG_GENERIC, LOG_CRIT, "Couldn't set reuse port socket option");
ABORT(R_INTERNAL);
}
}
break;
default:
ABORT(R_INTERNAL);
@ -556,10 +577,10 @@ int NrSocket::create(nr_transport_addr *addr) {
// Set nonblocking
PRSocketOptionData option;
option.option = PR_SockOpt_Nonblocking;
option.value.non_blocking = PR_TRUE;
status = PR_SetSocketOption(fd_, &option);
PRSocketOptionData opt_nonblock;
opt_nonblock.option = PR_SockOpt_Nonblocking;
opt_nonblock.value.non_blocking = PR_TRUE;
status = PR_SetSocketOption(fd_, &opt_nonblock);
if (status != PR_SUCCESS) {
r_log(LOG_GENERIC, LOG_CRIT, "Couldn't make socket nonblocking");
ABORT(R_INTERNAL);
@ -573,6 +594,7 @@ int NrSocket::create(nr_transport_addr *addr) {
// Finally, register with the STS
rv = stservice->AttachSocket(fd_, this);
if (!NS_SUCCEEDED(rv)) {
r_log(LOG_GENERIC, LOG_CRIT, "Couldn't attach socket to STS");
ABORT(R_INTERNAL);
}
@ -743,6 +765,7 @@ int NrSocket::write(const void *msg, size_t len, size_t *written) {
if (status < 0) {
if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
ABORT(R_WOULDBLOCK);
r_log(LOG_GENERIC, LOG_INFO, "Error in write");
ABORT(R_IO_ERROR);
}
@ -765,6 +788,7 @@ int NrSocket::read(void* buf, size_t maxlen, size_t *len) {
if (status < 0) {
if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
ABORT(R_WOULDBLOCK);
r_log(LOG_GENERIC, LOG_INFO, "Error in read");
ABORT(R_IO_ERROR);
}
if (status == 0)
@ -776,6 +800,95 @@ abort:
return(_status);
}
int NrSocket::listen(int backlog) {
ASSERT_ON_THREAD(ststhread_);
int32_t status;
int _status;
assert(fd_);
status = PR_Listen(fd_, backlog);
if (status != PR_SUCCESS) {
ABORT(R_IO_ERROR);
}
_status=0;
abort:
return(_status);
}
int NrSocket::accept(nr_transport_addr *addrp, nr_socket **sockp) {
ASSERT_ON_THREAD(ststhread_);
int _status, r;
PRStatus status;
PRFileDesc *ret;
PRNetAddr nfrom;
NrSocket *sock=nullptr;
nsresult rv;
nsCOMPtr<nsISocketTransportService> stservice =
do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
PRSocketOptionData option;
if (NS_FAILED(rv)) {
ABORT(R_INTERNAL);
}
assert(fd_);
ret = PR_Accept(fd_, &nfrom, PR_INTERVAL_NO_WAIT);
if (!ret) {
if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
ABORT(R_WOULDBLOCK);
ABORT(R_IO_ERROR);
}
if((r=nr_praddr_to_transport_addr(&nfrom,addrp,my_addr_.protocol,0)))
ABORT(r);
sock = new NrSocket();
sock->fd_=ret;
nr_transport_addr_copy(&sock->my_addr_, &my_addr_);
// Set nonblocking
option.option = PR_SockOpt_Nonblocking;
option.value.non_blocking = PR_TRUE;
status = PR_SetSocketOption(ret, &option);
if (status != PR_SUCCESS) {
r_log(LOG_GENERIC, LOG_CRIT, "Couldn't make socket nonblocking");
ABORT(R_INTERNAL);
}
// Remember our thread.
sock->ststhread_ = do_QueryInterface(stservice, &rv);
if (NS_FAILED(rv))
ABORT(R_INTERNAL);
// Finally, register with the STS
rv = stservice->AttachSocket(ret, sock);
if (NS_FAILED(rv)) {
ABORT(R_INTERNAL);
}
sock->connect_invoked_ = true;
r = nr_socket_create_int(static_cast<void *>(sock),
sock->vtbl(), sockp);
if (r)
ABORT(r);
// Add a reference so that we can delete it in destroy()
sock->AddRef();
_status=0;
abort:
if (_status) {
delete sock;
}
return(_status);
}
NS_IMPL_ISUPPORTS(NrSocketIpcProxy, nsIUDPSocketInternal)
nsresult
@ -1168,6 +1281,16 @@ int NrSocketIpc::read(void* buf, size_t maxlen, size_t *len) {
return R_INTERNAL;
}
int NrSocketIpc::listen(int backlog) {
MOZ_ASSERT(false);
return R_INTERNAL;
}
int NrSocketIpc::accept(nr_transport_addr *addrp, nr_socket **sockp) {
MOZ_ASSERT(false);
return R_INTERNAL;
}
// IO thread executors
void NrSocketIpc::create_i(const nsACString &host, const uint16_t port) {
ASSERT_ON_THREAD(io_thread_);
@ -1295,9 +1418,12 @@ static int nr_socket_local_write(void *obj,const void *msg, size_t len,
size_t *written);
static int nr_socket_local_read(void *obj,void * restrict buf, size_t maxlen,
size_t *len);
static int nr_socket_local_listen(void *obj, int backlog);
static int nr_socket_local_accept(void *obj, nr_transport_addr *addrp,
nr_socket **sockp);
static nr_socket_vtbl nr_socket_local_vtbl={
1,
2,
nr_socket_local_destroy,
nr_socket_local_sendto,
nr_socket_local_recvfrom,
@ -1306,7 +1432,9 @@ static nr_socket_vtbl nr_socket_local_vtbl={
nr_socket_local_connect,
nr_socket_local_write,
nr_socket_local_read,
nr_socket_local_close
nr_socket_local_close,
nr_socket_local_listen,
nr_socket_local_accept
};
int nr_socket_local_create(void *obj, nr_transport_addr *addr, nr_socket **sockp) {
@ -1415,6 +1543,19 @@ static int nr_socket_local_connect(void *obj, nr_transport_addr *addr) {
return sock->connect(addr);
}
static int nr_socket_local_listen(void *obj, int backlog) {
NrSocket *sock = static_cast<NrSocket *>(obj);
return sock->listen(backlog);
}
static int nr_socket_local_accept(void *obj, nr_transport_addr *addrp,
nr_socket **sockp) {
NrSocket *sock = static_cast<NrSocket *>(obj);
return sock->accept(addrp, sockp);
}
// Implement async api
int NR_async_wait(NR_SOCKET sock, int how, NR_async_cb cb,void *cb_arg,
char *function,int line) {

View File

@ -70,6 +70,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Stub declaration for nICEr type
typedef struct nr_socket_vtbl_ nr_socket_vtbl;
typedef struct nr_socket_ nr_socket;
namespace mozilla {
@ -98,6 +99,8 @@ public:
virtual int connect(nr_transport_addr *addr) = 0;
virtual int write(const void *msg, size_t len, size_t *written) = 0;
virtual int read(void* buf, size_t maxlen, size_t *len) = 0;
virtual int listen(int backlog) = 0;
virtual int accept(nr_transport_addr *addrp, nr_socket **sockp) = 0;
// Implementations of the async_event APIs
virtual int async_wait(int how, NR_async_cb cb, void *cb_arg,
@ -165,6 +168,8 @@ public:
virtual int connect(nr_transport_addr *addr) override;
virtual int write(const void *msg, size_t len, size_t *written) override;
virtual int read(void* buf, size_t maxlen, size_t *len) override;
virtual int listen(int backlog) override;
virtual int accept(nr_transport_addr *addrp, nr_socket **sockp) override;
protected:
virtual ~NrSocket() {
@ -230,6 +235,8 @@ public:
virtual int connect(nr_transport_addr *addr) override;
virtual int write(const void *msg, size_t len, size_t *written) override;
virtual int read(void* buf, size_t maxlen, size_t *len) override;
virtual int listen(int backlog) override;
virtual int accept(nr_transport_addr *addrp, nr_socket **sockp) override;
private:
virtual ~NrSocketIpc();

View File

@ -202,16 +202,14 @@ static nr_ice_crypto_vtbl nr_ice_crypto_nss_vtbl = {
nr_crypto_nss_md5
};
nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server,
const std::string &transport) const {
nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server) const {
int r;
int transport_int;
memset(server, 0, sizeof(nr_ice_stun_server));
if (transport == kNrIceTransportUdp) {
transport_int = IPPROTO_UDP;
} else if (transport == kNrIceTransportTcp) {
transport_int = IPPROTO_TCP;
if (transport_ == kNrIceTransportUdp) {
server->transport = IPPROTO_UDP;
} else if (transport_ == kNrIceTransportTcp) {
server->transport = IPPROTO_TCP;
} else {
MOZ_ASSERT(false);
return NS_ERROR_FAILURE;
@ -219,7 +217,7 @@ nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server,
if (has_addr_) {
r = nr_praddr_to_transport_addr(&addr_, &server->u.addr,
transport_int, 0);
server->transport, 0);
if (r) {
return NS_ERROR_FAILURE;
}
@ -240,19 +238,10 @@ nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server *server,
nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server *server) const {
memset(server, 0, sizeof(nr_ice_turn_server));
nsresult rv = ToNicerStunStruct(&server->turn_server, transport_);
nsresult rv = ToNicerStunStruct(&server->turn_server);
if (NS_FAILED(rv))
return rv;
if (transport_ == kNrIceTransportUdp) {
server->transport = IPPROTO_UDP;
} else if (transport_ == kNrIceTransportTcp) {
server->transport = IPPROTO_TCP;
} else {
MOZ_ASSERT(false);
return NS_ERROR_FAILURE;
}
if (username_.empty())
return NS_ERROR_INVALID_ARG;
if (password_.empty())
@ -407,6 +396,9 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_PEER_RFLX, 110);
NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_HOST, 126);
NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED, 5);
NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_SRV_RFLX_TCP, 99);
NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_PEER_RFLX_TCP, 109);
NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_HOST_TCP, 125);
NR_reg_set_uchar((char *)NR_ICE_REG_PREF_TYPE_RELAYED_TCP, 0);
if (set_interface_priorities) {
@ -438,6 +430,7 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
int32_t stun_client_maximum_transmits = 7;
int32_t ice_trickle_grace_period = 5000;
int32_t ice_tcp_so_sock_count = 3;
#ifndef MOZILLA_XPCOMRT_API
nsresult res;
nsCOMPtr<nsIPrefService> prefs =
@ -452,6 +445,9 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
branch->GetIntPref(
"media.peerconnection.ice.trickle_grace_period",
&ice_trickle_grace_period);
branch->GetIntPref(
"media.peerconnection.ice.tcp_so_sock_count",
&ice_tcp_so_sock_count);
}
}
#endif
@ -459,6 +455,8 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
stun_client_maximum_transmits);
NR_reg_set_uint4((char *)NR_ICE_REG_TRICKLE_GRACE_PERIOD,
ice_trickle_grace_period);
NR_reg_set_int4((char *)NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT,
ice_tcp_so_sock_count);
if (allow_loopback) {
NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);

View File

@ -99,9 +99,10 @@ class NrIceStunServer {
}
// The main function to use. Will take either an address or a hostname.
static NrIceStunServer* Create(const std::string& addr, uint16_t port) {
static NrIceStunServer* Create(const std::string& addr, uint16_t port,
const char *transport = kNrIceTransportUdp) {
ScopedDeletePtr<NrIceStunServer> server(
new NrIceStunServer());
new NrIceStunServer(transport));
nsresult rv = server->Init(addr, port);
if (NS_FAILED(rv))
@ -110,12 +111,11 @@ class NrIceStunServer {
return server.forget();
}
nsresult ToNicerStunStruct(nr_ice_stun_server* server,
const std::string& transport =
kNrIceTransportUdp) const;
nsresult ToNicerStunStruct(nr_ice_stun_server* server) const;
protected:
NrIceStunServer() : addr_() {}
explicit NrIceStunServer(const char *transport) :
addr_(), transport_(transport) {}
nsresult Init(const std::string& addr, uint16_t port) {
PRStatus status = PR_StringToNetAddr(addr.c_str(), &addr_);
@ -141,6 +141,7 @@ class NrIceStunServer {
std::string host_;
uint16_t port_;
PRNetAddr addr_;
std::string transport_;
};
class NrIceTurnServer : public NrIceStunServer {
@ -165,11 +166,10 @@ class NrIceTurnServer : public NrIceStunServer {
NrIceTurnServer(const std::string& username,
const std::vector<unsigned char>& password,
const char *transport) :
username_(username), password_(password), transport_(transport) {}
NrIceStunServer(transport), username_(username), password_(password) {}
std::string username_;
std::vector<unsigned char> password_;
std::string transport_;
};
class NrIceProxyServer {

View File

@ -144,7 +144,24 @@ static bool ToNrIceCandidate(const nr_ice_candidate& candc,
return false;
}
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;
}
out->type = type;
out->tcp_type = tcp_type;
out->codeword = candc.codeword;
return true;
}

View File

@ -80,9 +80,17 @@ struct NrIceCandidate {
ICE_RELAYED
};
enum TcpType {
ICE_NONE,
ICE_ACTIVE,
ICE_PASSIVE,
ICE_SO
};
NrIceAddr cand_addr;
NrIceAddr local_addr;
Type type;
TcpType tcp_type;
std::string codeword;
};

View File

@ -59,6 +59,7 @@ class BufferedStunSocketTest : public ::testing::Test {
int r = nr_socket_buffered_stun_create(
dummy->get_nr_socket(),
kStunMessageLen,
TURN_TCP_FRAMING,
&test_socket_);
ASSERT_EQ(0, r);
dummy_ = dummy.forget(); // Now owned by test_socket_.

View File

@ -88,6 +88,15 @@ class DummySocket : public NrSocketBase {
return 0;
}
virtual int listen(int backlog) {
return 0;
}
virtual int accept(nr_transport_addr *addrp, nr_socket **sockp) {
return 0;
}
virtual int write(const void *msg, size_t len, size_t *written) {
size_t to_write = std::min(len, writable_);

View File

@ -94,6 +94,20 @@ static std::string IsRelayCandidate(const std::string& candidate) {
return std::string();
}
static std::string IsTcpCandidate(const std::string& candidate) {
if (candidate.find("TCP") != std::string::npos) {
return candidate;
}
return std::string();
}
static std::string IsTcpSoCandidate(const std::string& candidate) {
if (candidate.find("tcptype so") != std::string::npos) {
return candidate;
}
return std::string();
}
static std::string IsLoopbackCandidate(const std::string& candidate) {
if (candidate.find("127.0.0.") != std::string::npos) {
return candidate;
@ -130,6 +144,9 @@ bool operator<(const NrIceCandidate& lhs,
if (lhs.cand_addr.host == rhs.cand_addr.host) {
if (lhs.cand_addr.port == rhs.cand_addr.port) {
if (lhs.cand_addr.transport == rhs.cand_addr.transport) {
if (lhs.type == rhs.type) {
return lhs.tcp_type < rhs.tcp_type;
}
return lhs.type < rhs.type;
}
return lhs.cand_addr.transport < rhs.cand_addr.transport;
@ -315,17 +332,22 @@ class IceTestPeer : public sigslot::has_slots<> {
NS_DISPATCH_SYNC);
}
void SetStunServer(const std::string addr, uint16_t port) {
void SetStunServer(const std::string addr, uint16_t port,
const char* transport = kNrIceTransportUdp) {
if (addr.empty()) {
// Happens when MOZ_DISABLE_NONLOCAL_CONNECTIONS is set
return;
}
std::vector<NrIceStunServer> stun_servers;
ScopedDeletePtr<NrIceStunServer> server(NrIceStunServer::Create(addr,
port));
ScopedDeletePtr<NrIceStunServer> server(NrIceStunServer::Create(
addr, port, transport));
stun_servers.push_back(*server);
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
SetStunServers(stun_servers);
}
void SetStunServers(const std::vector<NrIceStunServer> &servers) {
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(servers)));
}
void UseTestStunServer() {
@ -589,6 +611,7 @@ class IceTestPeer : public sigslot::has_slots<> {
void DumpCandidate(std::string which, const NrIceCandidate& cand) {
std::string type;
std::string tcp_type;
std::string addr;
int port;
@ -621,6 +644,22 @@ class IceTestPeer : public sigslot::has_slots<> {
FAIL();
};
switch(cand.tcp_type) {
case NrIceCandidate::ICE_NONE:
break;
case NrIceCandidate::ICE_ACTIVE:
tcp_type = " tcptype=active";
break;
case NrIceCandidate::ICE_PASSIVE:
tcp_type = " tcptype=passive";
break;
case NrIceCandidate::ICE_SO:
tcp_type = " tcptype=so";
break;
default:
FAIL();
};
std::cerr << which
<< " --> "
@ -629,6 +668,9 @@ class IceTestPeer : public sigslot::has_slots<> {
<< addr
<< ":"
<< port
<< "/"
<< cand.cand_addr.transport
<< tcp_type
<< " codeword="
<< cand.codeword
<< std::endl;
@ -1096,7 +1138,42 @@ class IceGatherTest : public ::testing::Test {
TestStunServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
// Sets an additional stun server
peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
TestStunServer::GetInstance()->port());
TestStunServer::GetInstance()->port(),
kNrIceTransportUdp);
}
void UseFakeStunTcpServerWithResponse(const std::string& fake_addr,
uint16_t fake_port) {
EnsurePeer();
TestStunTcpServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
// Sets an additional stun server
peer_->SetStunServer(TestStunTcpServer::GetInstance()->addr(),
TestStunTcpServer::GetInstance()->port(),
kNrIceTransportTcp);
}
void UseFakeStunUdpTcpServersWithResponse(const std::string& fake_udp_addr,
uint16_t fake_udp_port,
const std::string& fake_tcp_addr,
uint16_t fake_tcp_port) {
EnsurePeer();
std::vector<NrIceStunServer> stun_servers;
stun_servers.push_back(*NrIceStunServer::Create(
TestStunServer::GetInstance()->addr(),
TestStunServer::GetInstance()->port(),
kNrIceTransportUdp));
stun_servers.push_back(*NrIceStunServer::Create(
TestStunTcpServer::GetInstance()->addr(),
TestStunTcpServer::GetInstance()->port(),
kNrIceTransportTcp));
TestStunServer::GetInstance()->SetResponseAddr(fake_udp_addr,
fake_udp_port);
TestStunTcpServer::GetInstance()->SetResponseAddr(fake_tcp_addr,
fake_tcp_port);
// Sets an additional stun server
peer_->SetStunServers(stun_servers);
}
void UseTestStunServer() {
@ -1108,11 +1185,15 @@ class IceGatherTest : public ::testing::Test {
// NB: Only does substring matching, watch out for stuff like "1.2.3.4"
// matching "21.2.3.47". " 1.2.3.4 " should not have false positives.
bool StreamHasMatchingCandidate(unsigned int stream,
const std::string& match) {
const std::string& match,
const std::string& match2 = "") {
std::vector<std::string> candidates = peer_->GetCandidates(stream);
for (size_t c = 0; c < candidates.size(); ++c) {
if (std::string::npos != candidates[c].find(match)) {
return true;
if (!match2.length() ||
std::string::npos != candidates[c].find(match2)) {
return true;
}
}
}
return false;
@ -1186,8 +1267,15 @@ class IceConnectTest : public ::testing::Test {
p1_->SetBlockUdp(block_udp_);
p2_->SetBlockUdp(block_udp_);
} else {
p1_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
p2_->SetStunServer(g_stun_server_address, kDefaultStunServerPort);
std::vector<NrIceStunServer> stun_servers;
stun_servers.push_back(*NrIceStunServer::Create(g_stun_server_address,
kDefaultStunServerPort, kNrIceTransportUdp));
stun_servers.push_back(*NrIceStunServer::Create(g_stun_server_address,
kDefaultStunServerPort, kNrIceTransportTcp));
p1_->SetStunServers(stun_servers);
p2_->SetStunServers(stun_servers);
}
p1_->Gather();
@ -1528,6 +1616,14 @@ TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddress) {
// TODO(jib@mozilla.com): ensure we get server reflexive candidates Bug 848094
}
TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddressTcp) {
EnsurePeer();
peer_->SetStunServer(g_stun_server_address, kDefaultStunServerPort,
kNrIceTransportTcp);
peer_->SetDNSResolver();
Gather();
}
TEST_F(IceGatherTest, TestGatherDNSStunServerHostname) {
if (g_stun_server_hostname.empty()) {
return;
@ -1539,6 +1635,40 @@ TEST_F(IceGatherTest, TestGatherDNSStunServerHostname) {
Gather();
}
TEST_F(IceGatherTest, TestGatherDNSStunServerHostnameTcp) {
EnsurePeer();
peer_->SetStunServer(g_stun_server_hostname, kDefaultStunServerPort,
kNrIceTransportTcp);
peer_->SetDNSResolver();
Gather();
}
TEST_F(IceGatherTest, TestGatherDNSStunServerHostnameBothUdpTcp) {
std::vector<NrIceStunServer> stun_servers;
EnsurePeer();
stun_servers.push_back(*NrIceStunServer::Create(g_stun_server_hostname,
kDefaultStunServerPort, kNrIceTransportUdp));
stun_servers.push_back(*NrIceStunServer::Create(g_stun_server_hostname,
kDefaultStunServerPort, kNrIceTransportTcp));
peer_->SetStunServers(stun_servers);
peer_->SetDNSResolver();
Gather();
}
TEST_F(IceGatherTest, TestGatherDNSStunServerIpAddressBothUdpTcp) {
std::vector<NrIceStunServer> stun_servers;
EnsurePeer();
stun_servers.push_back(*NrIceStunServer::Create(g_stun_server_address,
kDefaultStunServerPort, kNrIceTransportUdp));
stun_servers.push_back(*NrIceStunServer::Create(g_stun_server_address,
kDefaultStunServerPort, kNrIceTransportTcp));
peer_->SetStunServers(stun_servers);
peer_->SetDNSResolver();
Gather();
}
TEST_F(IceGatherTest, TestGatherDNSStunBogusHostname) {
EnsurePeer();
peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort);
@ -1546,6 +1676,14 @@ TEST_F(IceGatherTest, TestGatherDNSStunBogusHostname) {
Gather();
}
TEST_F(IceGatherTest, TestGatherDNSStunBogusHostnameTcp) {
EnsurePeer();
peer_->SetStunServer(kBogusStunServerHostname, kDefaultStunServerPort,
kNrIceTransportTcp);
peer_->SetDNSResolver();
Gather();
}
TEST_F(IceGatherTest, TestGatherTurn) {
EnsurePeer();
if (g_turn_server.empty())
@ -1609,6 +1747,12 @@ TEST_F(IceGatherTest, VerifyTestStunServer) {
ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.133 3333 "));
}
TEST_F(IceGatherTest, VerifyTestStunTcpServer) {
UseFakeStunTcpServerWithResponse("192.0.2.233", 3333);
Gather();
ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.233 3333 typ srflx", " tcptype "));
}
TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddr) {
UseFakeStunServerWithResponse("0.0.0.0", 3333);
Gather(kDefaultTimeout * 3);
@ -1637,6 +1781,30 @@ TEST_F(IceGatherTest, TestStunServerTrickle) {
ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1"));
}
TEST_F(IceGatherTest, TestStunTcpServerTrickle) {
UseFakeStunTcpServerWithResponse("192.0.3.1", 3333);
TestStunTcpServer::GetInstance()->SetActive(false);
Gather(0);
ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
TestStunTcpServer::GetInstance()->SetActive(true);
WaitForGather();
ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
}
TEST_F(IceGatherTest, TestStunTcpAndUdpServerTrickle) {
UseFakeStunUdpTcpServersWithResponse("192.0.2.1", 3333, "192.0.3.1", 3333);
TestStunServer::GetInstance()->SetActive(false);
TestStunTcpServer::GetInstance()->SetActive(false);
Gather(0);
ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
TestStunServer::GetInstance()->SetActive(true);
TestStunTcpServer::GetInstance()->SetActive(true);
WaitForGather();
ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
}
TEST_F(IceConnectTest, TestGather) {
AddStream("first", 1);
ASSERT_TRUE(Gather());
@ -1655,6 +1823,26 @@ TEST_F(IceConnectTest, TestConnect) {
Connect();
}
TEST_F(IceConnectTest, TestConnectTcp) {
AddStream("first", 1);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsTcpCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
Connect();
}
//TCP SO tests works on localhost only with delay applied:
// tc qdisc add dev lo root netem delay 10ms
TEST_F(IceConnectTest, DISABLED_TestConnectTcpSo) {
AddStream("first", 1);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsTcpSoCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
Connect();
}
TEST_F(IceConnectTest, TestLoopbackOnlySortOf) {
Init(false, true);
AddStream("first", 1);
@ -2104,6 +2292,28 @@ TEST_F(IceConnectTest, TestSendReceive) {
SendReceive();
}
TEST_F(IceConnectTest, TestSendReceiveTcp) {
AddStream("first", 1);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsTcpCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
Connect();
SendReceive();
}
//TCP SO tests works on localhost only with delay applied:
// tc qdisc add dev lo root netem delay 10ms
TEST_F(IceConnectTest, DISABLED_TestSendReceiveTcpSo) {
AddStream("first", 1);
ASSERT_TRUE(Gather());
SetCandidateFilter(IsTcpSoCandidate);
SetExpectedTypes(NrIceCandidate::Type::ICE_HOST,
NrIceCandidate::Type::ICE_HOST, kNrIceTransportTcp);
Connect();
SendReceive();
}
TEST_F(IceConnectTest, TestConnectTurn) {
if (g_turn_server.empty())
return;
@ -2607,11 +2817,17 @@ int main(int argc, char **argv)
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunTcpServer::GetInstance), NS_DISPATCH_SYNC);
int rv = RUN_ALL_TESTS();
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC);
test_utils->sts_target()->Dispatch(
WrapRunnableNM(&TestStunTcpServer::ShutdownInstance), NS_DISPATCH_SYNC);
delete test_utils;
return rv;
}

View File

@ -8,6 +8,7 @@ if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
CppUnitTests([
'buffered_stun_socket_unittest',
'ice_unittest',
'multi_tcp_socket_unittest',
'nrappkit_unittest',
'proxy_tunnel_socket_unittest',
'rlogringbuffer_unittest',

View File

@ -0,0 +1,401 @@
/* -*- 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/. */
#include <iostream>
#include <vector>
#include "mozilla/Scoped.h"
#include "mozilla/Atomics.h"
#include "runnable_utils.h"
extern "C" {
#include "nr_api.h"
#include "nr_socket.h"
#include "transport_addr.h"
#include "ice_ctx.h"
#include "nr_socket_multi_tcp.h"
}
#include "mtransport_test_utils.h"
#include "nr_socket_prsock.h"
#include "nricectx.h"
#include "nricemediastream.h"
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"
#include "gtest_utils.h"
using namespace mozilla;
MtransportTestUtils *test_utils;
namespace {
class MultiTcpSocketTest : public ::testing::Test {
public:
MultiTcpSocketTest()
:socks(3,nullptr),
readable(false),
ice_ctx_(NrIceCtx::Create("stun", true))
{}
~MultiTcpSocketTest() {
test_utils->sts_target()->Dispatch(
WrapRunnable(
this, &MultiTcpSocketTest::Shutdown_s),
NS_DISPATCH_SYNC);
}
DISALLOW_COPY_ASSIGN(MultiTcpSocketTest);
static void SockReadable(NR_SOCKET s, int how, void *arg) {
MultiTcpSocketTest *obj=static_cast<MultiTcpSocketTest *>(arg);
obj->SetReadable(true);
}
void Shutdown_s() {
ice_ctx_ = nullptr;
for (std::vector<nr_socket *>::iterator it=socks.begin();
it!=socks.end(); ++it) {
nr_socket_destroy(&(*it));
}
}
void Create_s(nr_socket_tcp_type tcp_type, nr_socket *stun_server_socket,
int use_framing, nr_socket **sock) {
nr_transport_addr local;
static unsigned short port_s = 40000;
int r;
if (stun_server_socket) {
nr_transport_addr stun_addr;
int port;
char stun_host[1000];
r = nr_socket_getaddr(stun_server_socket, &stun_addr);
ASSERT_EQ(0, r);
r = nr_transport_addr_get_port(&stun_addr, &port);
ASSERT_EQ(0, r);
r = nr_transport_addr_get_addrstring(&stun_addr, &stun_host[0],
sizeof(stun_host));
ASSERT_EQ(0, r);
std::vector<NrIceStunServer> stun_servers;
ScopedDeletePtr<NrIceStunServer> server(NrIceStunServer::Create(
stun_host, port, kNrIceTransportTcp));
stun_servers.push_back(*server);
ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
}
r = 1;
for (int tries=10; tries && r; --tries) {
r = nr_ip4_str_port_to_transport_addr(
(char *)"127.0.0.1", port_s++, IPPROTO_TCP, &local);
ASSERT_EQ(0, r);
r = nr_socket_multi_tcp_create(ice_ctx_->ctx(),
&local, tcp_type, 1, use_framing, 2048, sock);
}
ASSERT_EQ(0, r);
printf("Created socket on %s\n", local.as_string);
r = nr_socket_multi_tcp_set_readable_cb(*sock,
&MultiTcpSocketTest::SockReadable, this);
ASSERT_EQ(0, r);
}
nr_socket *Create(nr_socket_tcp_type tcp_type,
nr_socket *stun_server_socket = NULL,
int use_framing = 1) {
nr_socket *sock=nullptr;
test_utils->sts_target()->Dispatch(
WrapRunnable(
this, &MultiTcpSocketTest::Create_s, tcp_type,
stun_server_socket, use_framing, &sock),
NS_DISPATCH_SYNC);
return sock;
}
void Listen_s(nr_socket *sock) {
nr_transport_addr addr;
int r=nr_socket_getaddr(sock, &addr);
ASSERT_EQ(0, r);
printf("Listen on %s\n", addr.as_string);
r = nr_socket_listen(sock, 1);
ASSERT_EQ(0, r);
}
void Listen(nr_socket *sock) {
test_utils->sts_target()->Dispatch(
WrapRunnable(
this, &MultiTcpSocketTest::Listen_s, sock),
NS_DISPATCH_SYNC);
}
void Connect_s(nr_socket *from, nr_socket *to) {
nr_transport_addr addr_to;
nr_transport_addr addr_from;
int r=nr_socket_getaddr(to, &addr_to);
ASSERT_EQ(0, r);
r=nr_socket_getaddr(from, &addr_from);
ASSERT_EQ(0, r);
printf("Connect from %s to %s\n", addr_from.as_string, addr_to.as_string);
r=nr_socket_connect(from, &addr_to);
ASSERT_EQ(0, r);
}
void Connect(nr_socket *from, nr_socket *to) {
test_utils->sts_target()->Dispatch(
WrapRunnable(
this, &MultiTcpSocketTest::Connect_s, from, to),
NS_DISPATCH_SYNC);
}
void ConnectSo_s(nr_socket *so1, nr_socket *so2) {
nr_transport_addr addr_so1;
nr_transport_addr addr_so2;
int r=nr_socket_getaddr(so1, &addr_so1);
ASSERT_EQ(0, r);
r=nr_socket_getaddr(so2, &addr_so2);
ASSERT_EQ(0, r);
printf("Connect SO %s <-> %s\n", addr_so1.as_string, addr_so2.as_string);
r=nr_socket_connect(so1, &addr_so2);
ASSERT_EQ(0, r);
r=nr_socket_connect(so2, &addr_so1);
ASSERT_EQ(0, r);
}
void ConnectSo(nr_socket *from, nr_socket *to) {
test_utils->sts_target()->Dispatch(
WrapRunnable(
this, &MultiTcpSocketTest::ConnectSo_s, from, to),
NS_DISPATCH_SYNC);
}
void SendData_s(nr_socket *from, nr_socket *to, const char *data,
size_t len) {
nr_transport_addr addr_from, addr_to;
int r=nr_socket_getaddr(to, &addr_to);
ASSERT_EQ(0, r);
r=nr_socket_getaddr(from, &addr_from);
ASSERT_EQ(0, r);
printf("Send %s -> %s\n", addr_from.as_string, addr_to.as_string);
r=nr_socket_sendto(from, data, len, 0, &addr_to);
ASSERT_EQ(0, r);
}
void SendData(nr_socket *from, nr_socket *to, const char *data, size_t len) {
test_utils->sts_target()->Dispatch(
WrapRunnable(
this, &MultiTcpSocketTest::SendData_s, from, to, data, len),
NS_DISPATCH_SYNC);
}
void RecvData_s(nr_socket *expected_from, nr_socket *sent_to,
const char *expected_data, size_t expected_len) {
char received_data[expected_len+1];
nr_transport_addr addr_from, addr_to;
nr_transport_addr retaddr;
size_t retlen;
int r=nr_socket_getaddr(sent_to, &addr_to);
ASSERT_EQ(0, r);
r=nr_socket_getaddr(expected_from, &addr_from);
ASSERT_EQ(0, r);
printf("Receive %s <- %s\n", addr_to.as_string, addr_from.as_string);
r=nr_socket_recvfrom(sent_to, received_data, expected_len+1,
&retlen, 0, &retaddr);
ASSERT_EQ(0, r);
r=nr_transport_addr_cmp(&retaddr, &addr_from,
NR_TRANSPORT_ADDR_CMP_MODE_ALL);
ASSERT_EQ(0, r);
ASSERT_EQ(expected_len, retlen);
r=memcmp(expected_data, received_data, retlen);
ASSERT_EQ(0, r);
}
void RecvData(nr_socket *expected_from, nr_socket *sent_to,
const char *expected_data, size_t expected_len) {
ASSERT_TRUE_WAIT(IsReadable(), 1000);
test_utils->sts_target()->Dispatch(
WrapRunnable(
this, &MultiTcpSocketTest::RecvData_s, expected_from, sent_to,
expected_data, expected_len),
NS_DISPATCH_SYNC);
SetReadable(false);
}
void TransferData(nr_socket *from, nr_socket *to, const char *data,
size_t len) {
SendData(from, to, data, len);
RecvData(from, to, data, len);
}
protected:
bool IsReadable() const {
return readable;
}
void SetReadable(bool r) {
readable=r;
}
std::vector<nr_socket *> socks;
Atomic<bool> readable;
nsRefPtr<NrIceCtx> ice_ctx_;
};
}
TEST_F(MultiTcpSocketTest, TestListen) {
socks[0] = Create(TCP_TYPE_PASSIVE);
Listen(socks[0]);
}
TEST_F(MultiTcpSocketTest, TestConnect) {
socks[0] = Create(TCP_TYPE_PASSIVE);
socks[1] = Create(TCP_TYPE_ACTIVE);
socks[2] = Create(TCP_TYPE_ACTIVE);
Listen(socks[0]);
Connect(socks[1], socks[0]);
Connect(socks[2], socks[0]);
}
TEST_F(MultiTcpSocketTest, TestTransmit) {
const char data[] = "TestTransmit";
socks[0] = Create(TCP_TYPE_ACTIVE);
socks[1] = Create(TCP_TYPE_PASSIVE);
Listen(socks[1]);
Connect(socks[0], socks[1]);
TransferData(socks[0], socks[1], data, sizeof(data));
TransferData(socks[1], socks[0], data, sizeof(data));
}
TEST_F(MultiTcpSocketTest, TestTwoSendsBeforeReceives) {
const char data1[] = "TestTwoSendsBeforeReceives";
const char data2[] = "2nd data";
socks[0] = Create(TCP_TYPE_ACTIVE);
socks[1] = Create(TCP_TYPE_PASSIVE);
Listen(socks[1]);
Connect(socks[0], socks[1]);
SendData(socks[0], socks[1], data1, sizeof(data1));
SendData(socks[0], socks[1], data2, sizeof(data2));
RecvData(socks[0], socks[1], data1, sizeof(data1));
RecvData(socks[0], socks[1], data2, sizeof(data2));
}
TEST_F(MultiTcpSocketTest, TestTwoActiveBidirectionalTransmit) {
const char data[] = "TestTwoActiveBidirectionalTransmit";
socks[0] = Create(TCP_TYPE_PASSIVE);
socks[1] = Create(TCP_TYPE_ACTIVE);
socks[2] = Create(TCP_TYPE_ACTIVE);
Listen(socks[0]);
Connect(socks[1], socks[0]);
Connect(socks[2], socks[0]);
TransferData(socks[1], socks[0], data, sizeof(data));
TransferData(socks[0], socks[1], data, sizeof(data));
TransferData(socks[2], socks[0], data, sizeof(data));
TransferData(socks[0], socks[2], data, sizeof(data));
}
TEST_F(MultiTcpSocketTest, TestTwoPassiveBidirectionalTransmit) {
const char data[] = "TestTwoPassiveBidirectionalTransmit";
socks[0] = Create(TCP_TYPE_PASSIVE);
socks[1] = Create(TCP_TYPE_PASSIVE);
socks[2] = Create(TCP_TYPE_ACTIVE);
Listen(socks[0]);
Listen(socks[1]);
Connect(socks[2], socks[0]);
Connect(socks[2], socks[1]);
TransferData(socks[2], socks[0], data, sizeof(data));
TransferData(socks[0], socks[2], data, sizeof(data));
TransferData(socks[2], socks[1], data, sizeof(data));
TransferData(socks[1], socks[2], data, sizeof(data));
}
TEST_F(MultiTcpSocketTest, TestActivePassiveWithStunServerMockup) {
/* Fake STUN message able to pass the nr_is_stun_msg check
used in nr_socket_buffered_stun */
const char stunMessage[] = {
'\x00', '\x01', '\x00', '\x04', '\x21', '\x12', '\xa4', '\x42',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0c', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x1c', '\xed', '\xca', '\xfe'
};
const char data[] = "TestActivePassiveWithStunServerMockup";
socks[0] = Create(TCP_TYPE_PASSIVE, NULL, 0); // stun server socket
Listen(socks[0]);
socks[1] = Create(TCP_TYPE_PASSIVE, socks[0]);
Listen(socks[1]);
socks[2] = Create(TCP_TYPE_ACTIVE, socks[0]);
TransferData(socks[1], socks[0], stunMessage, sizeof(stunMessage));
TransferData(socks[0], socks[1], stunMessage, sizeof(stunMessage));
Connect(socks[2], socks[1]);
TransferData(socks[2], socks[1], data, sizeof(data));
TransferData(socks[1], socks[2], data, sizeof(data));
}
TEST_F(MultiTcpSocketTest, TestConnectTwoSo) {
socks[0] = Create(TCP_TYPE_SO);
socks[1] = Create(TCP_TYPE_SO);
ConnectSo(socks[0], socks[1]);
}
// test works on localhost only with delay applied:
// tc qdisc add dev lo root netem delay 5ms
TEST_F(MultiTcpSocketTest, DISABLED_TestTwoSoBidirectionalTransmit) {
const char data[] = "TestTwoSoBidirectionalTransmit";
socks[0] = Create(TCP_TYPE_SO);
socks[1] = Create(TCP_TYPE_SO);
ConnectSo(socks[0], socks[1]);
TransferData(socks[0], socks[1], data, sizeof(data));
TransferData(socks[1], socks[0], data, sizeof(data));
}
TEST_F(MultiTcpSocketTest, TestBigData) {
char buf1[2048];
char buf2[1024];
for(unsigned i=0; i<sizeof(buf1); ++i) {
buf1[i]=i&0xff;
}
for(unsigned i=0; i<sizeof(buf2); ++i) {
buf2[i]=(i+0x80)&0xff;
}
socks[0] = Create(TCP_TYPE_ACTIVE);
socks[1] = Create(TCP_TYPE_PASSIVE);
Listen(socks[1]);
Connect(socks[0], socks[1]);
TransferData(socks[0], socks[1], buf1, sizeof(buf1));
TransferData(socks[0], socks[1], buf2, sizeof(buf2));
// opposite dir
SendData(socks[1], socks[0], buf2, sizeof(buf2));
SendData(socks[1], socks[0], buf1, sizeof(buf1));
RecvData(socks[1], socks[0], buf2, sizeof(buf2));
RecvData(socks[1], socks[0], buf1, sizeof(buf1));
}
int main(int argc, char **argv)
{
test_utils = new MtransportTestUtils();
// Start the tests
::testing::InitGoogleTest(&argc, argv);
int rv = RUN_ALL_TESTS();
delete test_utils;
return rv;
}

View File

@ -92,6 +92,7 @@ extern "C" {
#include "local_addr.h"
#include "stun_util.h"
#include "registry.h"
#include "nr_socket_multi_tcp.h"
}
#include "stunserver.h"
@ -154,7 +155,7 @@ static int nr_socket_wrapped_set_send_addr(nr_socket *sock, nr_transport_addr *a
}
static nr_socket_vtbl nr_socket_wrapped_vtbl = {
1,
2,
nr_socket_wrapped_destroy,
nr_socket_wrapped_sendto,
nr_socket_wrapped_recvfrom,
@ -163,7 +164,9 @@ static nr_socket_vtbl nr_socket_wrapped_vtbl = {
0,
0,
0,
nr_socket_wrapped_close
nr_socket_wrapped_close,
0,
0
};
int nr_socket_wrapped_create(nr_socket *inner, nr_socket **outp) {
@ -184,7 +187,9 @@ int nr_socket_wrapped_create(nr_socket *inner, nr_socket **outp) {
// Note: Calling Create() at static init time is not going to be safe, since
// we have no reason to expect this will be initted to a nullptr yet.
TestStunServer* TestStunServer::instance;
TestStunTcpServer* TestStunTcpServer::instance;
uint16_t TestStunServer::instance_port = 3478;
uint16_t TestStunTcpServer::instance_port = 3478;
TestStunServer::~TestStunServer() {
// TODO(ekr@rtfm.com): Put this on the right thread.
@ -209,31 +214,36 @@ TestStunServer::~TestStunServer() {
delete response_addr_;
}
int TestStunServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) {
int TestStunServer::SetInternalPort(nr_local_addr* addr, uint16_t port) {
if (nr_transport_addr_set_port(&addr->addr, port)) {
MOZ_MTLOG(ML_ERROR, "Couldn't set port");
return R_INTERNAL;
}
if (nr_transport_addr_set_port(&addr->addr, port)) {
MOZ_MTLOG(ML_ERROR, "Couldn't set port");
return R_INTERNAL;
}
if (nr_transport_addr_fmt_addr_string(&addr->addr)) {
MOZ_MTLOG(ML_ERROR, "Couldn't re-set addr string");
return R_INTERNAL;
}
if (nr_transport_addr_fmt_addr_string(&addr->addr)) {
MOZ_MTLOG(ML_ERROR, "Couldn't re-set addr string");
return R_INTERNAL;
}
if (nr_socket_local_create(nullptr, &addr->addr, &listen_sock_)) {
MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket");
return R_ALREADY;
}
return 0;
return 0;
}
TestStunServer* TestStunServer::Create() {
NR_reg_init(NR_REG_MODE_LOCAL);
int TestStunServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) {
ScopedDeletePtr<TestStunServer> server(new TestStunServer());
int r = SetInternalPort(addr, port);
if (r)
return r;
if (nr_socket_local_create(nullptr, &addr->addr, &listen_sock_)) {
MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket");
return R_ALREADY;
}
return 0;
}
int TestStunServer::Initialize() {
nr_local_addr addrs[100];
int addr_ct;
int r;
@ -241,19 +251,18 @@ TestStunServer* TestStunServer::Create() {
r = nr_stun_find_local_addresses(addrs, 100, &addr_ct);
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't retrieve addresses");
return nullptr;
return R_INTERNAL;
}
if (addr_ct < 1) {
MOZ_MTLOG(ML_ERROR, "No local addresses");
return nullptr;
return R_INTERNAL;
}
NR_SOCKET fd;
int tries = 100;
while (tries--) {
// Bind to the first address (arbitrarily) on configured port (default 3478)
r = server->TryOpenListenSocket(&addrs[0], instance_port);
r = TryOpenListenSocket(&addrs[0], instance_port);
// We interpret R_ALREADY to mean the addr is probably in use. Try another.
// Otherwise, it either worked or it didn't, and we check below.
if (r != R_ALREADY) {
@ -263,27 +272,21 @@ TestStunServer* TestStunServer::Create() {
}
if (r) {
return nullptr;
return R_INTERNAL;
}
r = nr_socket_getfd(server->listen_sock_, &fd);
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't get fd");
return nullptr;
}
r = nr_socket_wrapped_create(server->listen_sock_, &server->send_sock_);
r = nr_socket_wrapped_create(listen_sock_, &send_sock_);
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't create send socket");
return nullptr;
return R_INTERNAL;
}
r = nr_stun_server_ctx_create(const_cast<char *>("Test STUN server"),
server->send_sock_,
&server->stun_server_);
send_sock_,
&stun_server_);
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't create STUN server");
return nullptr;
return R_INTERNAL;
}
// Cache the address and port.
@ -292,11 +295,29 @@ TestStunServer* TestStunServer::Create() {
sizeof(addr_string));
if (r) {
MOZ_MTLOG(ML_ERROR, "Failed to convert listen addr to a string representation");
return nullptr;
return R_INTERNAL;
}
server->listen_addr_ = addr_string;
server->listen_port_ = instance_port;
listen_addr_ = addr_string;
listen_port_ = instance_port;
return 0;
}
TestStunServer* TestStunServer::Create() {
NR_reg_init(NR_REG_MODE_LOCAL);
ScopedDeletePtr<TestStunServer> server(new TestStunServer());
if (server->Initialize())
return nullptr;
NR_SOCKET fd;
int r = nr_socket_getfd(server->listen_sock_, &fd);
if (r) {
MOZ_MTLOG(ML_ERROR, "Couldn't get fd");
return nullptr;
}
NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server.get());
@ -451,4 +472,73 @@ void TestStunServer::Reset() {
response_addr_ = nullptr;
}
// TestStunTcpServer
void TestStunTcpServer::ConfigurePort(uint16_t port) {
instance_port = port;
}
TestStunTcpServer* TestStunTcpServer::GetInstance() {
if (!instance)
instance = Create();
MOZ_ASSERT(instance);
return instance;
}
void TestStunTcpServer::ShutdownInstance() {
delete instance;
instance = nullptr;
}
int TestStunTcpServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) {
addr->addr.protocol=IPPROTO_TCP;
int r = SetInternalPort(addr, port);
if (r)
return r;
if (ice_ctx_ == NULL)
ice_ctx_ = NrIceCtx::Create("stun", true);
//TODO (nils@mozilla.com) can we replace this with a more basic TCP socket
// alternative which would allow us to remove the framing argument from the
// nr_socket_multi_tcp_create() call?
if(nr_socket_multi_tcp_create(ice_ctx_->ctx(),
&addr->addr, TCP_TYPE_PASSIVE, 0, 0, 2048,
&listen_sock_)) {
MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket");
return R_ALREADY;
}
if(nr_socket_listen(listen_sock_, 10)) {
MOZ_MTLOG(ML_ERROR, "Couldn't listen on socket");
return R_ALREADY;
}
return 0;
}
TestStunTcpServer* TestStunTcpServer::Create() {
NR_reg_init(NR_REG_MODE_LOCAL);
ScopedDeletePtr<TestStunTcpServer> server(new TestStunTcpServer());
server->Initialize();
nr_socket_multi_tcp_set_readable_cb(server->listen_sock_,
&TestStunServer::readable_cb, server.get());
return server.forget();
}
TestStunTcpServer::~TestStunTcpServer() {
ice_ctx_ = nullptr;
nr_socket_destroy(&listen_sock_);
}
} // close namespace

View File

@ -31,7 +31,7 @@ class TestStunServer {
static void ConfigurePort(uint16_t port);
static TestStunServer *Create();
~TestStunServer();
virtual ~TestStunServer();
void SetActive(bool active);
void SetDelay(uint32_t delay_ms);
@ -46,40 +46,62 @@ class TestStunServer {
void Reset();
private:
protected:
TestStunServer()
: listen_sock_(nullptr),
: listen_port_(0),
listen_sock_(nullptr),
send_sock_(nullptr),
stun_server_(nullptr),
active_(true),
delay_ms_(0),
initial_ct_(0),
response_addr_(nullptr),
timer_handle_(nullptr),
listen_port_(0) {}
void Process(const uint8_t *msg, size_t len, nr_transport_addr *addr_in);
int TryOpenListenSocket(nr_local_addr* addr, uint16_t port);
timer_handle_(nullptr) {}
int SetInternalPort(nr_local_addr* addr, uint16_t port);
int Initialize();
static void readable_cb(NR_SOCKET sock, int how, void *cb_arg);
private:
void Process(const uint8_t *msg, size_t len, nr_transport_addr *addr_in);
virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port);
static void process_cb(NR_SOCKET sock, int how, void *cb_arg);
protected:
std::string listen_addr_;
uint16_t listen_port_;
nr_socket *listen_sock_;
nr_socket *send_sock_;
nr_stun_server_ctx *stun_server_;
private:
bool active_;
uint32_t delay_ms_;
uint32_t initial_ct_;
nr_transport_addr *response_addr_;
void *timer_handle_;
std::map<std::string, uint32_t> received_ct_;
std::string listen_addr_;
uint16_t listen_port_;
static TestStunServer* instance;
static uint16_t instance_port;
};
} // End of namespace mozilla
class TestStunTcpServer: public TestStunServer {
public:
static TestStunTcpServer *GetInstance();
static void ShutdownInstance();
static void ConfigurePort(uint16_t port);
virtual ~TestStunTcpServer();
protected:
TestStunTcpServer()
: ice_ctx_(nullptr) {}
nsRefPtr<NrIceCtx> ice_ctx_;
private:
virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port);
static TestStunTcpServer *Create();
static TestStunTcpServer* instance;
static uint16_t instance_port;
};
} // End of namespace mozilla
#endif

View File

@ -124,7 +124,7 @@ class TurnClient : public ::testing::Test {
if (protocol_ == IPPROTO_TCP) {
int r =
nr_socket_buffered_stun_create(real_socket_, 100000,
nr_socket_buffered_stun_create(real_socket_, 100000, TURN_TCP_FRAMING,
&buffered_socket_);
ASSERT_EQ(0, r);
net_socket_ = buffered_socket_;

View File

@ -74,6 +74,8 @@
"./src/net/nr_socket.h",
#"./src/net/nr_socket_local.c",
"./src/net/nr_socket_local.h",
"./src/net/nr_socket_multi_tcp.c",
"./src/net/nr_socket_multi_tcp.h",
"./src/net/transport_addr.c",
"./src/net/transport_addr.h",
"./src/net/transport_addr_reg.c",

View File

@ -62,6 +62,7 @@ static char *RCSSTRING __UNUSED__="$Id: ice_candidate.c,v 1.2 2008/04/28 17:59:0
#include "ice_util.h"
#include "nr_socket_turn.h"
#include "nr_socket.h"
#include "nr_socket_multi_tcp.h"
static int next_automatic_preference = 224;
@ -89,6 +90,7 @@ void nr_ice_candidate_compute_codeword(nr_ice_candidate *cand)
}
char *nr_ice_candidate_type_names[]={0,"host","srflx","prflx","relay",0};
char *nr_ice_candidate_tcp_type_names[]={0,"active","passive","so",0};
static const char *nr_ctype_name(nr_ice_candidate_type ctype) {
assert(ctype<CTYPE_MAX && ctype>0);
@ -98,6 +100,14 @@ static const char *nr_ctype_name(nr_ice_candidate_type ctype) {
return nr_ice_candidate_type_names[ctype];
}
static const char *nr_tcp_type_name(nr_socket_tcp_type tcp_type) {
assert(tcp_type<TCP_TYPE_MAX && tcp_type>0);
if (tcp_type <= 0 || tcp_type >= TCP_TYPE_MAX) {
return "ERROR";
}
return nr_ice_candidate_tcp_type_names[tcp_type];
}
static int nr_ice_candidate_format_stun_label(char *label, size_t size, nr_ice_candidate *cand)
{
int _status;
@ -122,7 +132,7 @@ static int nr_ice_candidate_format_stun_label(char *label, size_t size, nr_ice_c
return(_status);
}
int nr_ice_candidate_create(nr_ice_ctx *ctx,nr_ice_component *comp,nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp)
int nr_ice_candidate_create(nr_ice_ctx *ctx,nr_ice_component *comp,nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_socket_tcp_type tcp_type, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp)
{
nr_ice_candidate *cand=0;
nr_ice_candidate *tmp=0;
@ -136,6 +146,7 @@ int nr_ice_candidate_create(nr_ice_ctx *ctx,nr_ice_component *comp,nr_ice_socket
cand->isock=isock;
cand->osock=osock;
cand->type=ctype;
cand->tcp_type=tcp_type;
cand->stun_server=stun_server;
cand->component_id=component_id;
cand->component=comp;
@ -168,6 +179,16 @@ int nr_ice_candidate_create(nr_ice_ctx *ctx,nr_ice_component *comp,nr_ice_socket
assert(0); /* Can't happen */
ABORT(R_BAD_ARGS);
}
if (tcp_type) {
size_t slen=strlen(label)+1; /* plus space going to be added*/
if (slen<sizeof(label)) {
label[slen-1]=' ';
strncpy(label+slen, nr_tcp_type_name(tcp_type), sizeof(label)-slen-1);
label[sizeof(label)-1]=0;
}
}
if(!(cand->label=r_strdup(label)))
ABORT(R_NO_MEMORY);
@ -348,45 +369,93 @@ int nr_ice_candidate_compute_priority(nr_ice_candidate *cand)
UCHAR type_preference;
UCHAR interface_preference;
UCHAR stun_priority;
UCHAR direction_priority=0;
int r,_status;
if (cand->base.protocol != IPPROTO_UDP && cand->base.protocol != IPPROTO_TCP){
r_log(LOG_ICE,LOG_ERR,"Unknown protocol type %u",
(unsigned int)cand->base.protocol);
ABORT(R_INTERNAL);
}
switch(cand->type){
case HOST:
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_HOST,&type_preference))
ABORT(r);
if(cand->base.protocol == IPPROTO_UDP) {
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_HOST,&type_preference))
ABORT(r);
} else if(cand->base.protocol == IPPROTO_TCP) {
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_HOST_TCP,&type_preference))
ABORT(r);
} else
ABORT(R_INTERNAL);
stun_priority=0;
break;
case RELAYED:
if(cand->base.protocol == IPPROTO_UDP) {
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED,&type_preference))
ABORT(r);
}
else if(cand->base.protocol == IPPROTO_TCP) {
} else if(cand->base.protocol == IPPROTO_TCP) {
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED_TCP,&type_preference))
ABORT(r);
}
else {
r_log(LOG_ICE,LOG_ERR,"Unknown protocol type %u",
(unsigned int)cand->base.protocol);
} else
ABORT(R_INTERNAL);
}
stun_priority=255-cand->stun_server->index;
stun_priority=31-cand->stun_server->index;
break;
case SERVER_REFLEXIVE:
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_SRV_RFLX,&type_preference))
ABORT(r);
stun_priority=255-cand->stun_server->index;
if(cand->base.protocol == IPPROTO_UDP) {
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_SRV_RFLX,&type_preference))
ABORT(r);
} else if(cand->base.protocol == IPPROTO_TCP) {
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_SRV_RFLX_TCP,&type_preference))
ABORT(r);
} else
ABORT(R_INTERNAL);
stun_priority=31-cand->stun_server->index;
break;
case PEER_REFLEXIVE:
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_PEER_RFLX,&type_preference))
ABORT(r);
if(cand->base.protocol == IPPROTO_UDP) {
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_PEER_RFLX,&type_preference))
ABORT(r);
} else if(cand->base.protocol == IPPROTO_TCP) {
if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_PEER_RFLX_TCP,&type_preference))
ABORT(r);
} else
ABORT(R_INTERNAL);
stun_priority=0;
break;
default:
ABORT(R_INTERNAL);
}
if(cand->base.protocol == IPPROTO_TCP){
switch (cand->tcp_type) {
case TCP_TYPE_ACTIVE:
if (cand->type == HOST)
direction_priority=6;
else
direction_priority=4;
break;
case TCP_TYPE_PASSIVE:
if (cand->type == HOST)
direction_priority=4;
else
direction_priority=2;
break;
case TCP_TYPE_SO:
if (cand->type == HOST)
direction_priority=2;
else
direction_priority=6;
break;
case TCP_TYPE_NONE:
break;
case TCP_TYPE_MAX:
default:
assert(0);
ABORT(R_INTERNAL);
}
}
if(type_preference > 126)
r_log(LOG_ICE,LOG_ERR,"Illegal type preference %d",type_preference);
@ -429,9 +498,13 @@ int nr_ice_candidate_compute_priority(nr_ice_candidate *cand)
}
}
assert(stun_priority < 32);
assert(direction_priority < 8);
cand->priority=
(type_preference << 24) |
(interface_preference << 16) |
(direction_priority << 13) |
(stun_priority << 8) |
(256 - cand->component_id);
@ -455,7 +528,6 @@ int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, vo
{
int r,_status;
int protocol=NR_RESOLVE_PROTOCOL_STUN;
int transport=IPPROTO_UDP;
cand->done_cb=ready_cb;
cand->cb_arg=cb_arg;
@ -475,7 +547,6 @@ int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, vo
#ifdef USE_TURN
case RELAYED:
protocol=NR_RESOLVE_PROTOCOL_TURN;
transport=cand->u.relayed.server->transport;
/* Fall through */
#endif
case SERVER_REFLEXIVE:
@ -497,7 +568,7 @@ int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, vo
resource.domain_name=cand->stun_server->u.dnsname.host;
resource.port=cand->stun_server->u.dnsname.port;
resource.stun_turn=protocol;
resource.transport_protocol=transport;
resource.transport_protocol=cand->stun_server->transport;
/* Try to resolve */
if(!cand->ctx->resolver) {
@ -550,6 +621,11 @@ static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr)
if(r=nr_transport_addr_copy(&cand->stun_server_addr,addr))
ABORT(r);
if (cand->tcp_type == TCP_TYPE_PASSIVE || cand->tcp_type == TCP_TYPE_SO){
if (r=nr_socket_multi_tcp_stun_server_connect(cand->osock, addr))
ABORT(r);
}
/* Now start initializing */
if(r=nr_ice_candidate_initialize2(cand))
ABORT(r);
@ -713,6 +789,8 @@ static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_ar
case NR_STUN_CLIENT_STATE_DONE:
/* Copy the address */
nr_transport_addr_copy(&cand->addr, &cand->u.srvrflx.stun->results.stun_binding_response.mapped_addr);
cand->addr.protocol=cand->base.protocol;
nr_transport_addr_fmt_addr_string(&cand->addr);
nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
cand->state=NR_ICE_CAND_STATE_INITIALIZED;
/* Execute the ready callback */
@ -834,8 +912,8 @@ int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int ma
ABORT(r);
if(r=nr_transport_addr_get_port(&cand->addr,&port))
ABORT(r);
snprintf(attr,maxlen,"candidate:%s %d UDP %u %s %d typ %s",
cand->foundation, cand->component_id, cand->priority, addr, port,
snprintf(attr,maxlen,"candidate:%s %d %s %u %s %d typ %s",
cand->foundation, cand->component_id, cand->addr.protocol==IPPROTO_UDP?"UDP":"TCP",cand->priority, addr, port,
nr_ctype_name(cand->type));
len=strlen(attr); attr+=len; maxlen-=len;
@ -867,6 +945,12 @@ int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int ma
ABORT(R_INTERNAL);
break;
}
if (cand->base.protocol==IPPROTO_TCP && cand->tcp_type){
len=strlen(attr); attr+=len; maxlen-=len;
snprintf(attr,maxlen," tcptype %s",nr_tcp_type_name(cand->tcp_type));
}
_status=0;
abort:
return(_status);

View File

@ -59,6 +59,7 @@ struct nr_ice_candidate_ {
nr_ice_media_stream *stream; /* The media stream this is associated with */
nr_ice_component *component; /* The component this is associated with */
nr_ice_candidate_type type; /* The type of the candidate (S 4.1.1) */
nr_socket_tcp_type tcp_type;
UCHAR component_id; /* The component id (S 4.1.2.1) */
nr_transport_addr addr; /* The advertised address;
JDR calls this the candidate */
@ -97,9 +98,10 @@ struct nr_ice_candidate_ {
};
extern char *nr_ice_candidate_type_names[];
extern char *nr_ice_candidate_tcp_type_names[];
int nr_ice_candidate_create(struct nr_ice_ctx_ *ctx,nr_ice_component *component, nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp);
int nr_ice_candidate_create(struct nr_ice_ctx_ *ctx,nr_ice_component *component, nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_socket_tcp_type tcp_type, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp);
int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg);
void nr_ice_candidate_compute_codeword(nr_ice_candidate *cand);
int nr_ice_candidate_process_stun(nr_ice_candidate *cand, UCHAR *msg, int len, nr_transport_addr *faddr);

View File

@ -263,7 +263,7 @@ static void nr_ice_candidate_pair_stun_cb(NR_SOCKET s, int how, void *cb_arg)
if(!cand){
if(r=nr_ice_candidate_create(pair->pctx->ctx,
pair->local->component,pair->local->isock,pair->local->osock,
PEER_REFLEXIVE,0,pair->local->component->component_id,&cand))
PEER_REFLEXIVE,pair->local->tcp_type,0,pair->local->component->component_id,&cand))
ABORT(r);
if(r=nr_transport_addr_copy(&cand->addr,&pair->stun_client->results.ice_binding_response.mapped_addr))
ABORT(r);

View File

@ -46,7 +46,9 @@ static char *RCSSTRING __UNUSED__="$Id: ice_component.c,v 1.2 2008/04/28 17:59:0
#include "nr_socket_turn.h"
#include "nr_socket_wrapper.h"
#include "nr_socket_buffered_stun.h"
#include "nr_socket_multi_tcp.h"
#include "ice_reg.h"
#include "nr_crypto.h"
static int nr_ice_component_stun_server_default_cb(void *cb_arg,nr_stun_server_ctx *stun_ctx,nr_socket *sock, nr_stun_server_request *req, int *dont_free, int *error);
static int nr_ice_pre_answer_request_destroy(nr_ice_pre_answer_request **parp);
@ -173,6 +175,28 @@ int nr_ice_component_destroy(nr_ice_component **componentp)
return(0);
}
static int nr_ice_component_create_stun_server_ctx(nr_ice_component *component, nr_ice_socket *isock, nr_socket *sock, nr_transport_addr *addr, char *lufrag, Data *pwd)
{
char label[256];
int r,_status;
/* Create a STUN server context for this socket */
snprintf(label, sizeof(label), "server(%s)", addr->as_string);
if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server))
ABORT(r);
if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
ABORT(r);
/* Add the default STUN credentials so that we can respond before
we hear about the peer.*/
if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component))
ABORT(r);
_status = 0;
abort:
return(_status);
}
static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_component *component, nr_local_addr *addrs, int addr_ct, char *lufrag, Data *pwd)
{
nr_socket *sock;
@ -180,7 +204,6 @@ static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_compon
nr_ice_candidate *cand=0;
int i;
int j;
char label[256];
int r,_status;
/* Now one ice_socket for each address */
@ -201,10 +224,10 @@ static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_compon
continue;
}
if(r=nr_ice_socket_create(ctx,component,sock,&isock))
if(r=nr_ice_socket_create(ctx,component,sock,NR_ICE_SOCKET_TYPE_DGRAM,&isock))
ABORT(r);
/* Create one host candidate */
if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0,
if(r=nr_ice_candidate_create(ctx,component,isock,sock,HOST,0,0,
component->component_id,&cand))
ABORT(r);
@ -215,7 +238,7 @@ static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_compon
/* And a srvrflx candidate for each STUN server */
for(j=0;j<ctx->stun_server_ct;j++){
if(r=nr_ice_candidate_create(ctx,component,
isock,sock,SERVER_REFLEXIVE,
isock,sock,SERVER_REFLEXIVE,0,
&ctx->stun_servers[j],component->component_id,&cand))
ABORT(r);
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
@ -230,12 +253,12 @@ static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_compon
nr_ice_candidate *srvflx_cand;
/* Skip non-UDP */
if (ctx->turn_servers[j].transport != IPPROTO_UDP)
if (ctx->turn_servers[j].turn_server.transport != IPPROTO_UDP)
continue;
/* srvrflx */
if(r=nr_ice_candidate_create(ctx,component,
isock,sock,SERVER_REFLEXIVE,
isock,sock,SERVER_REFLEXIVE,0,
&ctx->turn_servers[j].turn_server,component->component_id,&cand))
ABORT(r);
cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
@ -250,7 +273,7 @@ static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_compon
if(r=nr_socket_turn_create(sock, &turn_sock))
ABORT(r);
if(r=nr_ice_candidate_create(ctx,component,
isock,turn_sock,RELAYED,
isock,turn_sock,RELAYED,0,
&ctx->turn_servers[j].turn_server,component->component_id,&cand))
ABORT(r);
cand->u.relayed.srvflx_candidate=srvflx_cand;
@ -263,15 +286,7 @@ static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_compon
#endif /* USE_TURN */
/* Create a STUN server context for this socket */
snprintf(label, sizeof(label), "server(%s)", addrs[i].addr.as_string);
if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server))
ABORT(r);
if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
ABORT(r);
/* Add the default STUN credentials so that we can respond before
we hear about the peer. */
if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component))
if ((r=nr_ice_component_create_stun_server_ctx(component,isock,sock,&addrs[i].addr,lufrag,pwd)))
ABORT(r);
STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
@ -282,20 +297,106 @@ static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_compon
return(_status);
}
static int nr_ice_component_get_port_from_ephemeral_range(uint16_t *port)
{
int _status, r;
void *buf = port;
if(r=nr_crypto_random_bytes(buf, 2))
ABORT(r);
*port|=0x8000; /* make it >= 0x8000 */
_status=0;
abort:
return(_status);
}
static int nr_ice_component_create_tcp_host_candidate(struct nr_ice_ctx_ *ctx,
nr_ice_component *component, nr_transport_addr *interface_addr, nr_socket_tcp_type tcp_type,
int so_sock_ct, char *lufrag, Data *pwd, nr_ice_socket **isock)
{
int r,_status;
nr_ice_candidate *cand=0;
int tries=3;
nr_ice_socket *isock_tmp=0;
nr_socket *nrsock=0;
nr_transport_addr addr;
uint16_t local_port;
if ((r=nr_transport_addr_copy(&addr,interface_addr)))
ABORT(r);
addr.protocol=IPPROTO_TCP;
do{
if (!tries--)
ABORT(r);
if((r=nr_ice_component_get_port_from_ephemeral_range(&local_port)))
ABORT(r);
if ((r=nr_transport_addr_set_port(&addr, local_port)))
ABORT(r);
if((r=nr_transport_addr_fmt_addr_string(&addr)))
ABORT(r);
/* It would be better to stop trying if there is error other than
port already used, but it'd require significant work to support this. */
r=nr_socket_multi_tcp_create(ctx,&addr,tcp_type,so_sock_ct,1,NR_STUN_MAX_MESSAGE_SIZE,&nrsock);
} while(r);
if((tcp_type == TCP_TYPE_PASSIVE) && (r=nr_socket_listen(nrsock,1)))
ABORT(r);
if((r=nr_ice_socket_create(ctx,component,nrsock,NR_ICE_SOCKET_TYPE_STREAM_TCP,&isock_tmp)))
ABORT(r);
/* nr_ice_socket took ownership of nrsock */
nrsock=NULL;
/* Create a STUN server context for this socket */
if ((r=nr_ice_component_create_stun_server_ctx(component,isock_tmp,isock_tmp->sock,&addr,lufrag,pwd)))
ABORT(r);
if((r=nr_ice_candidate_create(ctx,component,isock_tmp,isock_tmp->sock,HOST,tcp_type,0,
component->component_id,&cand)))
ABORT(r);
if (isock)
*isock=isock_tmp;
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
component->candidate_ct++;
STAILQ_INSERT_TAIL(&component->sockets,isock_tmp,entry);
_status=0;
abort:
if (_status) {
nr_ice_socket_destroy(&isock_tmp);
nr_socket_destroy(&nrsock);
}
return(_status);
}
static int nr_ice_component_initialize_tcp(struct nr_ice_ctx_ *ctx,nr_ice_component *component, nr_local_addr *addrs, int addr_ct, char *lufrag, Data *pwd)
{
nr_ice_socket *isock=0;
nr_ice_candidate *cand=0;
int i;
int j;
char label[256];
int r,_status;
int so_sock_ct=0;
r_log(LOG_ICE,LOG_DEBUG,"nr_ice_component_initialize_tcp");
/* Create a new relayed candidate for each addr/TURN server pair */
if(r=NR_reg_get_int4(NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT,&so_sock_ct)){
if(r!=R_NOT_FOUND)
ABORT(r);
}
for(i=0;i<addr_ct;i++){
char suppress;
nr_ice_socket *isock_psv=0;
nr_ice_socket *isock_so=0;
if(r=NR_reg_get2_char(NR_ICE_REG_SUPPRESS_INTERFACE_PRFX,addrs[i].addr.ifname,&suppress)){
if(r!=R_NOT_FOUND)
@ -306,24 +407,87 @@ static int nr_ice_component_initialize_tcp(struct nr_ice_ctx_ *ctx,nr_ice_compon
continue;
}
#ifdef USE_TURN
for(j=0;j<ctx->turn_server_ct;j++){
nr_transport_addr addr;
nr_socket *sock;
nr_socket *buffered_sock;
nr_socket *turn_sock;
/* passive host candidate */
if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
TCP_TYPE_PASSIVE, 0, lufrag, pwd, &isock_psv)))
ABORT(r);
/* Skip non-TCP */
if (ctx->turn_servers[j].transport != IPPROTO_TCP)
/* active host candidate */
if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
TCP_TYPE_ACTIVE, 0, lufrag, pwd, NULL)))
ABORT(r);
/* simultaneous-open host candidate */
if (so_sock_ct) {
if ((r=nr_ice_component_create_tcp_host_candidate(ctx, component, &addrs[i].addr,
TCP_TYPE_SO, so_sock_ct, lufrag, pwd, &isock_so)))
ABORT(r);
}
/* And srvrflx candidates for each STUN server */
for(j=0;j<ctx->stun_server_ct;j++){
if (ctx->stun_servers[j].transport!=IPPROTO_TCP)
continue;
/* Create a local socket */
if(r=nr_ice_candidate_create(ctx,component,
isock_psv,isock_psv->sock,SERVER_REFLEXIVE,TCP_TYPE_PASSIVE,
&ctx->stun_servers[j],component->component_id,&cand))
ABORT(r);
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
component->candidate_ct++;
cand=0;
if (so_sock_ct) {
if(r=nr_ice_candidate_create(ctx,component,
isock_so,isock_so->sock,SERVER_REFLEXIVE,TCP_TYPE_SO,
&ctx->stun_servers[j],component->component_id,&cand))
ABORT(r);
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
component->candidate_ct++;
cand=0;
}
}
#ifdef USE_TURN
/* Create a new relayed candidate for each addr/TURN server pair */
for(j=0;j<ctx->turn_server_ct;j++){
nr_transport_addr addr;
nr_socket *local_sock;
nr_socket *buffered_sock;
nr_socket *turn_sock;
nr_ice_socket *turn_isock;
/* Skip non-TCP */
if (ctx->turn_servers[j].turn_server.transport != IPPROTO_TCP)
continue;
/* Use TURN server to get srflx candidates */
if(r=nr_ice_candidate_create(ctx,component,
isock_psv,isock_psv->sock,SERVER_REFLEXIVE,TCP_TYPE_PASSIVE,
&ctx->turn_servers[j].turn_server,component->component_id,&cand))
ABORT(r);
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
component->candidate_ct++;
cand=0;
if (so_sock_ct) {
if(r=nr_ice_candidate_create(ctx,component,
isock_so,isock_so->sock,SERVER_REFLEXIVE,TCP_TYPE_SO,
&ctx->turn_servers[j].turn_server,component->component_id,&cand))
ABORT(r);
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
component->candidate_ct++;
cand=0;
}
/* Create relay candidate */
if ((r=nr_transport_addr_copy(&addr, &addrs[i].addr)))
ABORT(r);
addr.protocol = IPPROTO_TCP;
if ((r=nr_transport_addr_fmt_addr_string(&addr)))
ABORT(r);
if((r=nr_socket_factory_create_socket(ctx->socket_factory,&addr,&sock))){
/* Create a local socket */
if((r=nr_socket_factory_create_socket(ctx->socket_factory,&addr,&local_sock))){
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): couldn't create socket for address %s",ctx->label,addr.as_string);
continue;
}
@ -332,12 +496,12 @@ static int nr_ice_component_initialize_tcp(struct nr_ice_ctx_ *ctx,nr_ice_compon
if (ctx->turn_tcp_socket_wrapper) {
/* Wrap it */
if((r=nr_socket_wrapper_factory_wrap(ctx->turn_tcp_socket_wrapper, sock, &sock)))
if((r=nr_socket_wrapper_factory_wrap(ctx->turn_tcp_socket_wrapper, local_sock, &local_sock)))
ABORT(r);
}
/* Wrap it */
if((r=nr_socket_buffered_stun_create(sock, NR_STUN_MAX_MESSAGE_SIZE, &buffered_sock)))
if((r=nr_socket_buffered_stun_create(local_sock, NR_STUN_MAX_MESSAGE_SIZE, TURN_TCP_FRAMING, &buffered_sock)))
ABORT(r);
/* The TURN socket */
@ -345,12 +509,12 @@ static int nr_ice_component_initialize_tcp(struct nr_ice_ctx_ *ctx,nr_ice_compon
ABORT(r);
/* Create an ICE socket */
if((r=nr_ice_socket_create(ctx, component, buffered_sock, &isock)))
if((r=nr_ice_socket_create(ctx, component, buffered_sock, NR_ICE_SOCKET_TYPE_STREAM_TURN, &turn_isock)))
ABORT(r);
/* Attach ourselves to it */
if(r=nr_ice_candidate_create(ctx,component,
isock,turn_sock,RELAYED,
turn_isock,turn_sock,RELAYED,TCP_TYPE_NONE,
&ctx->turn_servers[j].turn_server,component->component_id,&cand))
ABORT(r);
cand->u.relayed.srvflx_candidate=NULL;
@ -360,21 +524,13 @@ static int nr_ice_component_initialize_tcp(struct nr_ice_ctx_ *ctx,nr_ice_compon
cand=0;
/* Create a STUN server context for this socket */
snprintf(label, sizeof(label), "server(%s)", addr.as_string);
if(r=nr_stun_server_ctx_create(label,sock,&isock->stun_server))
ABORT(r);
if(r=nr_ice_socket_register_stun_server(isock,isock->stun_server,&isock->stun_server_handle))
if ((r=nr_ice_component_create_stun_server_ctx(component,turn_isock,local_sock,&addr,lufrag,pwd)))
ABORT(r);
/* Add the default STUN credentials so that we can respond before
we hear about the peer.*/
if(r=nr_stun_server_add_default_client(isock->stun_server, lufrag, pwd, nr_ice_component_stun_server_default_cb, component))
ABORT(r);
STAILQ_INSERT_TAIL(&component->sockets,isock,entry);
STAILQ_INSERT_TAIL(&component->sockets,turn_isock,entry);
}
#endif /* USE_TURN */
}
#endif
_status = 0;
abort:
@ -422,7 +578,10 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
ABORT(r);
/* And the TCP candidates */
if (r=nr_ice_component_initialize_tcp(ctx, component, addrs, addr_ct, lufrag, &pwd))
ABORT(r);
/* TODO: This will fail when NrSocketIpc is used, therefore we ignore this result.
Remove this error ignore once there will be pref to turn off TCP */
if (r != R_REJECTED)
ABORT(r);
/* count the candidates that will be initialized */
cand=TAILQ_FIRST(&component->candidates);
@ -533,6 +692,7 @@ static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_tr
int remote_addr_matched;
nr_ice_cand_pair *found_invalid=0;
int r=0,_status;
int new_pcand_created=0;
r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d): received request from %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,req->src_addr.as_string);
@ -637,17 +797,32 @@ static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_tr
ABORT(R_NOT_FOUND);
}
/* We now need to make a peer reflexive */
if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) {
*error=(r==R_NO_MEMORY)?500:400;
ABORT(r);
/* Try to find matching peer active tcp candidate */
pcand=TAILQ_FIRST(&comp->candidates);
while(pcand){
if(pcand->tcp_type == TCP_TYPE_ACTIVE) {
if(!nr_transport_addr_cmp(&pcand->addr,&req->src_addr,NR_TRANSPORT_ADDR_CMP_MODE_ALL))
break;
}
pcand=TAILQ_NEXT(pcand,entry_comp);
}
if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY,&attr)){
r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label);
*error=487;
ABORT(R_BAD_DATA);
if (!pcand){
/* We now need to make a peer reflexive */
if(r=nr_ice_peer_peer_rflx_candidate_create(comp->stream->pctx->ctx,"prflx",comp,&req->src_addr,&pcand)) {
*error=(r==R_NO_MEMORY)?500:400;
ABORT(r);
}
new_pcand_created=1;
if(!nr_stun_message_has_attribute(sreq,NR_STUN_ATTR_PRIORITY,&attr)){
r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Rejecting stun request without priority",comp->stream->pctx->label);
*error=487;
ABORT(R_BAD_DATA);
}
pcand->priority=attr->u.priority;
}
pcand->priority=attr->u.priority;
pcand->state=NR_ICE_CAND_PEER_CANDIDATE_PAIRED;
if(r=nr_ice_candidate_pair_create(comp->stream->pctx,cand,pcand,
@ -664,8 +839,10 @@ static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_tr
}
/* Do this last, since any call to ABORT will destroy pcand */
TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp);
pcand=0;
if (new_pcand_created){
TAILQ_INSERT_TAIL(&comp->candidates,pcand,entry_comp);
pcand=0;
}
}
else{
/* OK, there was a pair, it's just invalid: According to Section
@ -715,7 +892,8 @@ static int nr_ice_component_process_incoming_check(nr_ice_component *comp, nr_tr
_status=0;
abort:
if(_status){
nr_ice_candidate_destroy(&pcand);
if (new_pcand_created)
nr_ice_candidate_destroy(&pcand);
assert(*error != 0);
if(r!=R_NO_MEMORY) assert(*error != 500);
}
@ -798,8 +976,17 @@ int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pco
break;
}
pcand=TAILQ_FIRST(&pcomp->candidates);
while(pcand){
TAILQ_FOREACH(pcand, &pcomp->candidates, entry_comp){
if (lcand->tcp_type && !pcand->tcp_type)
continue;
if (!lcand->tcp_type && pcand->tcp_type)
continue;
if (lcand->tcp_type == TCP_TYPE_ACTIVE && pcand->tcp_type != TCP_TYPE_PASSIVE)
continue;
if (lcand->tcp_type == TCP_TYPE_SO && pcand->tcp_type != TCP_TYPE_SO)
continue;
if (lcand->tcp_type == TCP_TYPE_PASSIVE)
continue;
/*
Two modes, depending on |pair_all_remote|
@ -825,8 +1012,6 @@ int nr_ice_component_pair_candidate(nr_ice_peer_ctx *pctx, nr_ice_component *pco
if(r=nr_ice_component_insert_pair(pcomp, pair))
ABORT(r);
}
pcand=TAILQ_NEXT(pcand,entry_comp);
}
done:

View File

@ -349,10 +349,10 @@ int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp)
ctx->stun_server_ct=0;
}
/* 255 is the max for our priority algorithm */
if(ctx->stun_server_ct>255){
r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Too many STUN servers specified: max=255", ctx->label);
ctx->stun_server_ct=255;
/* 31 is the max for our priority algorithm */
if(ctx->stun_server_ct>31){
r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Too many STUN servers specified: max=31", ctx->label);
ctx->stun_server_ct=31;
}
if(ctx->stun_server_ct>0){
@ -377,10 +377,10 @@ int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp)
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,"ICE(%s): Too many STUN/TURN servers specified: max=255", ctx->label);
ctx->turn_server_ct=255-ctx->stun_server_ct;
/* 31 is the max for our priority algorithm */
if((ctx->stun_server_ct+ctx->turn_server_ct)>31){
r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Too many STUN/TURN servers specified: max=31", ctx->label);
ctx->turn_server_ct=31-ctx->stun_server_ct;
}
#ifdef USE_TURN

View File

@ -62,11 +62,11 @@ typedef struct nr_ice_stun_server_ {
} dnsname;
} u;
int index;
int transport;
} nr_ice_stun_server;
typedef struct nr_ice_turn_server_ {
nr_ice_stun_server turn_server;
int transport;
char *username;
Data *password;
} nr_ice_turn_server;

View File

@ -124,6 +124,7 @@ nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_str
int i;
unsigned int component_id;
char *rel_addr=0;
unsigned char transport;
if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
ABORT(R_NO_MEMORY);
@ -178,8 +179,12 @@ nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_str
ABORT(R_BAD_DATA);
/* Protocol */
if (strncasecmp(str, "UDP", 3))
ABORT(R_BAD_DATA);
if (!strncasecmp(str, "UDP", 3))
transport=IPPROTO_UDP;
else if (!strncasecmp(str, "TCP", 3))
transport=IPPROTO_TCP;
else
ABORT(R_BAD_DATA);
fast_forward(&str, 3);
if (*str == '\0')
@ -222,7 +227,7 @@ nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_str
ABORT(R_BAD_DATA);
/* Assume v4 for now */
if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,IPPROTO_UDP,&cand->addr))
if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,transport,&cand->addr))
ABORT(r);
skip_to_past_space(&str);
@ -310,7 +315,7 @@ nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_str
ABORT(R_BAD_DATA);
/* Assume v4 for now */
if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,IPPROTO_UDP,&cand->base))
if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,transport,&cand->base))
ABORT(r);
skip_to_past_space(&str);
@ -324,6 +329,28 @@ nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_str
skip_whitespace(&str);
if (transport == IPPROTO_TCP && cand->type != RELAYED) {
/* Parse tcptype extension per RFC 6544 S 4.5 */
if (strncasecmp("tcptype ", str, 8))
ABORT(R_BAD_DATA);
fast_forward(&str, 8);
skip_whitespace(&str);
for (i = 1; nr_ice_candidate_tcp_type_names[i]; ++i) {
if(!strncasecmp(nr_ice_candidate_tcp_type_names[i], str, strlen(nr_ice_candidate_tcp_type_names[i]))) {
cand->tcp_type=i;
fast_forward(&str, strlen(nr_ice_candidate_tcp_type_names[i]));
break;
}
}
if (cand->tcp_type == 0)
ABORT(R_BAD_DATA);
if (*str && *str != ' ')
ABORT(R_BAD_DATA);
}
/* Ignore extensions per RFC 5245 S 15.1 */
#if 0
/* This used to be an assert, but we don't want to exit on invalid

View File

@ -39,30 +39,35 @@ using namespace std;
extern "C" {
#endif /* __cplusplus */
#define NR_ICE_REG_PREF_TYPE_HOST "ice.pref.type.host"
#define NR_ICE_REG_PREF_TYPE_RELAYED "ice.pref.type.relayed"
#define NR_ICE_REG_PREF_TYPE_SRV_RFLX "ice.pref.type.srv_rflx"
#define NR_ICE_REG_PREF_TYPE_PEER_RFLX "ice.pref.type.peer_rflx"
#define NR_ICE_REG_PREF_TYPE_HOST "ice.pref.type.host"
#define NR_ICE_REG_PREF_TYPE_RELAYED "ice.pref.type.relayed"
#define NR_ICE_REG_PREF_TYPE_SRV_RFLX "ice.pref.type.srv_rflx"
#define NR_ICE_REG_PREF_TYPE_PEER_RFLX "ice.pref.type.peer_rflx"
#define NR_ICE_REG_PREF_TYPE_HOST_TCP "ice.pref.type.host_tcp"
#define NR_ICE_REG_PREF_TYPE_RELAYED_TCP "ice.pref.type.relayed_tcp"
#define NR_ICE_REG_PREF_TYPE_SRV_RFLX_TCP "ice.pref.type.srv_rflx_tcp"
#define NR_ICE_REG_PREF_TYPE_PEER_RFLX_TCP "ice.pref.type.peer_rflx_tcp"
#define NR_ICE_REG_PREF_INTERFACE_PRFX "ice.pref.interface"
#define NR_ICE_REG_SUPPRESS_INTERFACE_PRFX "ice.suppress.interface"
#define NR_ICE_REG_STUN_SRV_PRFX "ice.stun.server"
#define NR_ICE_REG_STUN_SRV_ADDR "addr"
#define NR_ICE_REG_STUN_SRV_PORT "port"
#define NR_ICE_REG_STUN_SRV_PRFX "ice.stun.server"
#define NR_ICE_REG_STUN_SRV_ADDR "addr"
#define NR_ICE_REG_STUN_SRV_PORT "port"
#define NR_ICE_REG_TURN_SRV_PRFX "ice.turn.server"
#define NR_ICE_REG_TURN_SRV_ADDR "addr"
#define NR_ICE_REG_TURN_SRV_PORT "port"
#define NR_ICE_REG_TURN_SRV_BANDWIDTH "bandwidth"
#define NR_ICE_REG_TURN_SRV_LIFETIME "lifetime"
#define NR_ICE_REG_TURN_SRV_USERNAME "username"
#define NR_ICE_REG_TURN_SRV_PASSWORD "password"
#define NR_ICE_REG_TURN_SRV_PRFX "ice.turn.server"
#define NR_ICE_REG_TURN_SRV_ADDR "addr"
#define NR_ICE_REG_TURN_SRV_PORT "port"
#define NR_ICE_REG_TURN_SRV_BANDWIDTH "bandwidth"
#define NR_ICE_REG_TURN_SRV_LIFETIME "lifetime"
#define NR_ICE_REG_TURN_SRV_USERNAME "username"
#define NR_ICE_REG_TURN_SRV_PASSWORD "password"
#define NR_ICE_REG_KEEPALIVE_TIMER "ice.keepalive_timer"
#define NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT "ice.tcp.so_sock_count"
#define NR_ICE_REG_TRICKLE_GRACE_PERIOD "ice.trickle_grace_period"
#define NR_ICE_REG_KEEPALIVE_TIMER "ice.keepalive_timer"
#define NR_ICE_REG_TRICKLE_GRACE_PERIOD "ice.trickle_grace_period"
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -39,6 +39,7 @@ static char *RCSSTRING __UNUSED__="$Id: ice_socket.c,v 1.2 2008/04/28 17:59:01 e
#include "nr_api.h"
#include "ice_ctx.h"
#include "stun.h"
#include "nr_socket_multi_tcp.h"
static void nr_ice_socket_readable_cb(NR_SOCKET s, int how, void *cb_arg)
{
@ -60,12 +61,13 @@ static void nr_ice_socket_readable_cb(NR_SOCKET s, int how, void *cb_arg)
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Socket ready to read",sock->ctx->label);
/* Re-arm first! */
NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg);
if (sock->type != NR_ICE_SOCKET_TYPE_STREAM_TCP)
NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg);
if(r=nr_socket_recvfrom(sock->sock,buf,sizeof(buf),&len_s,0,&addr)){
if (r != R_WOULDBLOCK && (sock->type != NR_ICE_SOCKET_TYPE_DGRAM)) {
if (r != R_WOULDBLOCK && (sock->type == NR_ICE_SOCKET_TYPE_STREAM_TURN)) {
/* Report this error upward. Bug 946423 */
r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error on reliable socket. Abandoning.",sock->ctx->label);
r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error %d on reliable socket. Abandoning.",sock->ctx->label, r);
NR_ASYNC_CANCEL(s, NR_ASYNC_WAIT_READ);
}
return;
@ -190,7 +192,7 @@ static void nr_ice_socket_readable_cb(NR_SOCKET s, int how, void *cb_arg)
return;
}
int nr_ice_socket_create(nr_ice_ctx *ctx,nr_ice_component *comp, nr_socket *nsock, nr_ice_socket **sockp)
int nr_ice_socket_create(nr_ice_ctx *ctx,nr_ice_component *comp, nr_socket *nsock, int type, nr_ice_socket **sockp)
{
nr_ice_socket *sock=0;
NR_SOCKET fd;
@ -207,21 +209,28 @@ int nr_ice_socket_create(nr_ice_ctx *ctx,nr_ice_component *comp, nr_socket *nsoc
if(r=nr_socket_getaddr(nsock, &addr))
ABORT(r);
if (addr.protocol == IPPROTO_UDP) {
sock->type = NR_ICE_SOCKET_TYPE_DGRAM;
if (type == NR_ICE_SOCKET_TYPE_DGRAM) {
assert(addr.protocol == IPPROTO_UDP);
}
else {
assert(addr.protocol == IPPROTO_TCP);
sock->type = NR_ICE_SOCKET_TYPE_STREAM;
}
sock->type=type;
TAILQ_INIT(&sock->candidates);
TAILQ_INIT(&sock->stun_ctxs);
if(r=nr_socket_getfd(nsock,&fd))
ABORT(r);
NR_ASYNC_WAIT(fd,NR_ASYNC_WAIT_READ,nr_ice_socket_readable_cb,sock);
if (sock->type != NR_ICE_SOCKET_TYPE_STREAM_TCP){
if((r=nr_socket_getfd(nsock,&fd)))
ABORT(r);
NR_ASYNC_WAIT(fd,NR_ASYNC_WAIT_READ,nr_ice_socket_readable_cb,sock);
}
else {
/* in this case we can't hook up using NR_ASYNC_WAIT, because nr_socket_multi_tcp
consists of multiple nr_sockets and file descriptors. */
if((r=nr_socket_multi_tcp_set_readable_cb(nsock,nr_ice_socket_readable_cb,sock)))
ABORT(r);
}
*sockp=sock;
@ -273,13 +282,15 @@ int nr_ice_socket_close(nr_ice_socket *isock)
if (!isock||!isock->sock)
return(0);
nr_socket_getfd(isock->sock,&fd);
assert(isock->sock!=0);
if(fd != no_socket){
NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_READ);
NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_WRITE);
nr_socket_destroy(&isock->sock);
if (isock->type != NR_ICE_SOCKET_TYPE_STREAM_TCP){
nr_socket_getfd(isock->sock,&fd);
if(fd != no_socket){
NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_READ);
NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_WRITE);
}
}
nr_socket_destroy(&isock->sock);
return(0);
}

View File

@ -60,11 +60,11 @@ typedef struct nr_ice_stun_ctx_ {
} nr_ice_stun_ctx;
typedef struct nr_ice_socket_ {
int type;
#define NR_ICE_SOCKET_TYPE_DGRAM 1
#define NR_ICE_SOCKET_TYPE_STREAM 2
#define NR_ICE_SOCKET_TYPE_DGRAM 1
#define NR_ICE_SOCKET_TYPE_STREAM_TURN 2
#define NR_ICE_SOCKET_TYPE_STREAM_TCP 3
nr_socket *sock;
nr_ice_ctx *ctx;
@ -82,7 +82,7 @@ typedef struct nr_ice_socket_ {
typedef STAILQ_HEAD(nr_ice_socket_head_,nr_ice_socket_) nr_ice_socket_head;
int nr_ice_socket_create(struct nr_ice_ctx_ *ctx, struct nr_ice_component_ *comp, nr_socket *nsock, nr_ice_socket **sockp);
int nr_ice_socket_create(struct nr_ice_ctx_ *ctx, struct nr_ice_component_ *comp, nr_socket *nsock, int type, nr_ice_socket **sockp);
int nr_ice_socket_destroy(nr_ice_socket **isock);
int nr_ice_socket_close(nr_ice_socket *isock);
int nr_ice_socket_register_stun_client(nr_ice_socket *sock, nr_stun_client_ctx *srv,void **handle);

View File

@ -48,8 +48,8 @@ int nr_socket_create_int(void *obj, nr_socket_vtbl *vtbl, nr_socket **sockp)
if(!(sock=RCALLOC(sizeof(nr_socket))))
ABORT(R_NO_MEMORY);
assert(vtbl->version == 1);
if (vtbl->version != 1)
assert(vtbl->version >= 1 && vtbl->version <= 2);
if (vtbl->version < 1 || vtbl->version > 2)
ABORT(R_INTERNAL);
sock->obj=obj;
@ -136,6 +136,20 @@ int nr_socket_read(nr_socket *sock,void * restrict buf, size_t maxlen,
return sock->vtbl->sread(sock->obj, buf, maxlen, len);
}
int nr_socket_listen(nr_socket *sock, int backlog)
{
assert(sock->vtbl->version >=2 );
CHECK_DEFINED(listen);
return sock->vtbl->listen(sock->obj, backlog);
}
int nr_socket_accept(nr_socket *sock, nr_transport_addr *addrp, nr_socket **sockp)
{
assert(sock->vtbl->version >= 2);
CHECK_DEFINED(accept);
return sock->vtbl->accept(sock->obj, addrp, sockp);
}
int nr_socket_factory_create_int(void *obj,
nr_socket_factory_vtbl *vtbl, nr_socket_factory **factorypp)

View File

@ -52,8 +52,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define restrict __restrict
#endif
typedef enum {
TCP_TYPE_NONE=0,
TCP_TYPE_ACTIVE,
TCP_TYPE_PASSIVE,
TCP_TYPE_SO,
TCP_TYPE_MAX
} nr_socket_tcp_type;
typedef struct nr_socket_ nr_socket;
typedef struct nr_socket_vtbl_ {
UINT4 version; /* Currently 1 */
UINT4 version; /* Currently 2 */
int (*destroy)(void **obj);
int (*ssendto)(void *obj,const void *msg, size_t len, int flags,
nr_transport_addr *addr);
@ -65,12 +75,17 @@ typedef struct nr_socket_vtbl_ {
int (*swrite)(void *obj,const void *msg, size_t len, size_t *written);
int (*sread)(void *obj,void * restrict buf, size_t maxlen, size_t *len);
int (*close)(void *obj);
/* available since version 2 */
int (*listen)(void *obj, int backlog);
int (*accept)(void *obj, nr_transport_addr *addrp, nr_socket **sockp);
} nr_socket_vtbl;
typedef struct nr_socket_ {
struct nr_socket_ {
void *obj;
nr_socket_vtbl *vtbl;
} nr_socket;
};
typedef struct nr_socket_factory_vtbl_ {
int (*create_socket)(void *obj, nr_transport_addr *addr, nr_socket **sockp);
@ -95,6 +110,8 @@ int nr_socket_close(nr_socket *sock);
int nr_socket_connect(nr_socket *sock, nr_transport_addr *addr);
int nr_socket_write(nr_socket *sock,const void *msg, size_t len, size_t *written, int flags);
int nr_socket_read(nr_socket *sock, void * restrict buf, size_t maxlen, size_t *len, int flags);
int nr_socket_listen(nr_socket *sock, int backlog);
int nr_socket_accept(nr_socket *sock, nr_transport_addr *addrp, nr_socket **sockp);
int nr_socket_factory_create_int(void *obj, nr_socket_factory_vtbl *vtbl, nr_socket_factory **factorypp);
int nr_socket_factory_destroy(nr_socket_factory **factoryp);

View File

@ -0,0 +1,565 @@
/*
Copyright (c) 2007, Adobe Systems, Incorporated
Copyright (c) 2014, Mozilla
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Adobe Systems, Network Resonance nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <sys/types.h>
#include "nr_api.h"
#include "ice_ctx.h"
#include "nr_socket.h"
#include "nr_socket_local.h"
#include "nr_socket_multi_tcp.h"
#include "nr_socket_buffered_stun.h"
#include "async_timer.h"
typedef struct nr_tcp_socket_ctx_ {
nr_socket * inner;
nr_transport_addr remote_addr;
int is_framed;
TAILQ_ENTRY(nr_tcp_socket_ctx_) entry;
} nr_tcp_socket_ctx;
typedef TAILQ_HEAD(nr_tcp_socket_head_,nr_tcp_socket_ctx_) nr_tcp_socket_head;
static void nr_tcp_socket_readable_cb(NR_SOCKET s, int how, void *arg);
static int nr_tcp_socket_ctx_destroy(nr_tcp_socket_ctx **objp)
{
if (!objp || !*objp)
return(0);
nr_socket_destroy(&(*objp)->inner);
RFREE(*objp);
*objp=NULL;
return(0);
}
static int nr_tcp_socket_ctx_create(nr_socket *nrsock, int is_framed,
int max_pending, nr_tcp_socket_ctx **sockp)
{
int r, _status;
nr_tcp_socket_ctx *sock = 0;
nr_socket *tcpsock;
if (!(sock = RCALLOC(sizeof(nr_tcp_socket_ctx)))) {
nr_socket_destroy(&nrsock);
ABORT(R_NO_MEMORY);
}
if ((r=nr_socket_buffered_stun_create(nrsock, max_pending, is_framed ? ICE_TCP_FRAMING : TURN_TCP_FRAMING, &tcpsock))){
nr_socket_destroy(&nrsock);
ABORT(r);
}
sock->inner=tcpsock;
sock->is_framed=is_framed;
if ((r=nr_ip4_port_to_transport_addr(ntohl(INADDR_ANY), 0, IPPROTO_TCP, &sock->remote_addr)))
ABORT(r);
*sockp=sock;
_status=0;
abort:
if (_status) {
nr_tcp_socket_ctx_destroy(&sock);
}
return(_status);
}
static int nr_tcp_socket_ctx_initialize(nr_tcp_socket_ctx *tcpsock,
nr_transport_addr *addr, void* cb_arg)
{
int r, _status;
NR_SOCKET fd;
if ((r=nr_transport_addr_copy(&tcpsock->remote_addr, addr)))
ABORT(r);
if ((r=nr_socket_getfd(tcpsock->inner, &fd)))
ABORT(r);
NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, nr_tcp_socket_readable_cb, cb_arg);
_status=0;
abort:
return(_status);
}
typedef struct nr_socket_multi_tcp_ {
nr_ice_ctx *ctx;
nr_socket *listen_socket;
nr_tcp_socket_head sockets;
nr_socket_tcp_type tcp_type;
nr_transport_addr addr;
NR_async_cb readable_cb;
void *readable_cb_arg;
int max_pending;
int use_framing;
} nr_socket_multi_tcp;
static int nr_socket_multi_tcp_destroy(void **objp);
static int nr_socket_multi_tcp_sendto(void *obj,const void *msg, size_t len,
int flags, nr_transport_addr *to);
static int nr_socket_multi_tcp_recvfrom(void *obj,void * restrict buf,
size_t maxlen, size_t *len, int flags, nr_transport_addr *from);
static int nr_socket_multi_tcp_getaddr(void *obj, nr_transport_addr *addrp);
static int nr_socket_multi_tcp_close(void *obj);
static int nr_socket_multi_tcp_connect(void *sock, nr_transport_addr *addr);
static int nr_socket_multi_tcp_listen(void *obj, int backlog);
static nr_socket_vtbl nr_socket_multi_tcp_vtbl={
2,
nr_socket_multi_tcp_destroy,
nr_socket_multi_tcp_sendto,
nr_socket_multi_tcp_recvfrom,
0,
nr_socket_multi_tcp_getaddr,
nr_socket_multi_tcp_connect,
0,
0,
nr_socket_multi_tcp_close,
nr_socket_multi_tcp_listen,
0
};
static int nr_socket_multi_tcp_create_stun_server_socket(
nr_socket_multi_tcp *sock, nr_ice_stun_server * stun_server,
nr_transport_addr *addr, int max_pending)
{
int r, _status;
nr_tcp_socket_ctx *tcp_socket_ctx;
nr_socket * nrsock;
if (stun_server->transport!=IPPROTO_TCP)
return(0);
if ((r=nr_socket_factory_create_socket(sock->ctx->socket_factory,addr, &nrsock)))
ABORT(r);
/* This takes ownership of nrsock whether it fails or not. */
if ((r=nr_tcp_socket_ctx_create(nrsock, 0, max_pending, &tcp_socket_ctx)))
ABORT(r);
TAILQ_INSERT_TAIL(&sock->sockets, tcp_socket_ctx, entry);
if (stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
nr_transport_addr stun_server_addr;
nr_transport_addr_copy(&stun_server_addr, &stun_server->u.addr);
r=nr_socket_connect(tcp_socket_ctx->inner, &stun_server_addr);
if (!r && r!=R_WOULDBLOCK)
ABORT(r);
if ((r=nr_tcp_socket_ctx_initialize(tcp_socket_ctx, &stun_server_addr, sock)))
ABORT(r);
}
_status=0;
abort:
return(_status);
}
int nr_socket_multi_tcp_create(struct nr_ice_ctx_ *ctx,
nr_transport_addr *addr, nr_socket_tcp_type tcp_type,
int precreated_so_count, int use_framing, int max_pending,
nr_socket **sockp)
{
int i=0;
int r, _status;
nr_socket_multi_tcp *sock=0;
nr_tcp_socket_ctx *tcp_socket_ctx;
nr_socket * nrsock;
if (!(sock = RCALLOC(sizeof(nr_socket_multi_tcp))))
ABORT(R_NO_MEMORY);
TAILQ_INIT(&sock->sockets);
sock->ctx=ctx;
sock->max_pending=max_pending;
sock->tcp_type=tcp_type;
sock->use_framing=use_framing;
nr_transport_addr_copy(&sock->addr, addr);
if((tcp_type==TCP_TYPE_PASSIVE) &&
((r=nr_socket_factory_create_socket(sock->ctx->socket_factory, addr, &sock->listen_socket))))
ABORT(r);
if (tcp_type!=TCP_TYPE_ACTIVE) {
if (sock->ctx && sock->ctx->stun_servers) {
for (i=0; i<sock->ctx->stun_server_ct; ++i) {
if ((r=nr_socket_multi_tcp_create_stun_server_socket(sock,
sock->ctx->stun_servers+i, addr, max_pending)))
ABORT(r);
}
}
if (sock->ctx && sock->ctx->turn_servers) {
for (i=0; i<sock->ctx->turn_server_ct; ++i) {
if ((r=nr_socket_multi_tcp_create_stun_server_socket(sock,
&(sock->ctx->turn_servers[i]).turn_server, addr, max_pending)))
ABORT(r);
}
}
}
if ((tcp_type==TCP_TYPE_SO)) {
for (i=0; i<precreated_so_count; ++i) {
if ((r=nr_socket_factory_create_socket(sock->ctx->socket_factory, addr, &nrsock)))
ABORT(r);
/* This takes ownership of nrsock whether it fails or not. */
if ((r=nr_tcp_socket_ctx_create(nrsock, use_framing, max_pending, &tcp_socket_ctx))){
ABORT(r);
}
TAILQ_INSERT_TAIL(&sock->sockets, tcp_socket_ctx, entry);
}
}
if((r=nr_socket_create_int(sock, &nr_socket_multi_tcp_vtbl, sockp)))
ABORT(r);
_status=0;
abort:
if (_status) {
nr_socket_multi_tcp_destroy((void**)&sock);
}
return(_status);
}
int nr_socket_multi_tcp_set_readable_cb(nr_socket *sock,
NR_async_cb readable_cb, void *readable_cb_arg)
{
nr_socket_multi_tcp *mtcp_sock = (nr_socket_multi_tcp *)sock->obj;
mtcp_sock->readable_cb=readable_cb;
mtcp_sock->readable_cb_arg=readable_cb_arg;
return 0;
}
#define PREALLOC_CONNECT_FRAMED 0
#define PREALLOC_CONNECT_NON_FRAMED 1
#define PREALLOC_DONT_CONNECT_UNLESS_SO 2
static int nr_socket_multi_tcp_get_sock_connected_to(nr_socket_multi_tcp *sock,
nr_transport_addr *to, int preallocated_connect_mode, nr_socket **ret_sock)
{
int r, _status;
nr_tcp_socket_ctx *tcp_sock_ctx;
nr_socket * nrsock;
to->protocol=IPPROTO_TCP;
TAILQ_FOREACH(tcp_sock_ctx, &sock->sockets, entry) {
if (!nr_transport_addr_is_wildcard(&tcp_sock_ctx->remote_addr)) {
if (!nr_transport_addr_cmp(to, &tcp_sock_ctx->remote_addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
*ret_sock=tcp_sock_ctx->inner;
return(0);
}
}
}
tcp_sock_ctx=NULL;
/* not connected yet */
if (sock->tcp_type != TCP_TYPE_ACTIVE) {
if (preallocated_connect_mode == PREALLOC_DONT_CONNECT_UNLESS_SO && sock->tcp_type != TCP_TYPE_SO)
ABORT(R_FAILED);
/* find free preallocated socket and connect */
TAILQ_FOREACH(tcp_sock_ctx, &sock->sockets, entry) {
if (nr_transport_addr_is_wildcard(&tcp_sock_ctx->remote_addr)) {
if (preallocated_connect_mode == PREALLOC_CONNECT_NON_FRAMED && tcp_sock_ctx->is_framed)
continue;
if (preallocated_connect_mode != PREALLOC_CONNECT_NON_FRAMED && !tcp_sock_ctx->is_framed)
continue;
if ((r=nr_socket_connect(tcp_sock_ctx->inner, to))){
if (r!=R_WOULDBLOCK)
ABORT(r);
}
if ((r=nr_tcp_socket_ctx_initialize(tcp_sock_ctx, to, sock)))
ABORT(r);
*ret_sock=tcp_sock_ctx->inner;
return(0);
}
}
tcp_sock_ctx=NULL;
ABORT(R_FAILED);
}
/* if active type - create new socket for each new remote addr */
assert(sock->tcp_type == TCP_TYPE_ACTIVE);
/* ICE-TCP active type should always use framing */
assert(sock->use_framing);
if ((r=nr_socket_factory_create_socket(sock->ctx->socket_factory, &sock->addr, &nrsock)))
ABORT(r);
/* This takes ownership of nrsock whether it fails or not. */
if ((r=nr_tcp_socket_ctx_create(nrsock, 1, sock->max_pending, &tcp_sock_ctx))){
ABORT(r);
}
TAILQ_INSERT_TAIL(&sock->sockets, tcp_sock_ctx, entry);
if ((r=nr_socket_connect(tcp_sock_ctx->inner, to))){
if (r!=R_WOULDBLOCK)
ABORT(r);
}
if ((r=nr_tcp_socket_ctx_initialize(tcp_sock_ctx, to, sock)))
ABORT(r);
*ret_sock=tcp_sock_ctx->inner;
tcp_sock_ctx=NULL;
_status=0;
abort:
if (_status && tcp_sock_ctx) {
TAILQ_REMOVE(&sock->sockets, tcp_sock_ctx, entry);
nr_tcp_socket_ctx_destroy(&tcp_sock_ctx);
}
return(_status);
}
int nr_socket_multi_tcp_stun_server_connect(nr_socket *sock,
nr_transport_addr *addr)
{
int r, _status;
nr_socket_multi_tcp *mtcp_sock = (nr_socket_multi_tcp *)sock->obj;
nr_socket *nrsock;
assert(mtcp_sock->tcp_type != TCP_TYPE_ACTIVE);
if (mtcp_sock->tcp_type == TCP_TYPE_ACTIVE)
ABORT(R_INTERNAL);
if ((r=nr_socket_multi_tcp_get_sock_connected_to(mtcp_sock,addr,PREALLOC_CONNECT_NON_FRAMED,&nrsock)))
ABORT(r);
_status=0;
abort:
return(_status);
}
static int nr_socket_multi_tcp_destroy(void **objp)
{
nr_socket_multi_tcp *sock;
nr_tcp_socket_ctx *tcpsock;
NR_SOCKET fd;
if (!objp || !*objp)
return 0;
sock = (nr_socket_multi_tcp *)*objp;
*objp = 0;
/* Cancel waiting on the socket */
if (sock->listen_socket && !nr_socket_getfd(sock->listen_socket, &fd)) {
NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
}
nr_socket_destroy(&sock->listen_socket);
while (!TAILQ_EMPTY(&sock->sockets)) {
tcpsock = TAILQ_FIRST(&sock->sockets);
TAILQ_REMOVE(&sock->sockets, tcpsock, entry);
if (!nr_socket_getfd(tcpsock->inner, &fd)) {
NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
}
nr_tcp_socket_ctx_destroy(&tcpsock);
}
RFREE(sock);
return 0;
}
static int nr_socket_multi_tcp_sendto(void *obj,const void *msg, size_t len,
int flags, nr_transport_addr *to)
{
int r, _status;
nr_socket_multi_tcp *sock = (nr_socket_multi_tcp *)obj;
nr_socket *nrsock;
if ((r=nr_socket_multi_tcp_get_sock_connected_to(sock, to, PREALLOC_DONT_CONNECT_UNLESS_SO, &nrsock)))
ABORT(r);
if((r=nr_socket_sendto(nrsock, msg, len, flags, to)))
ABORT(r);
_status=0;
abort:
return(_status);
}
static int nr_socket_multi_tcp_recvfrom(void *obj,void * restrict buf,
size_t maxlen, size_t *len, int flags, nr_transport_addr *from)
{
int r, _status;
nr_socket_multi_tcp *sock = (nr_socket_multi_tcp *)obj;
nr_tcp_socket_ctx *tcpsock;
TAILQ_FOREACH(tcpsock, &sock->sockets, entry) {
if (nr_transport_addr_is_wildcard(&tcpsock->remote_addr))
continue;
r=nr_socket_recvfrom(tcpsock->inner, buf, maxlen, len, flags, from);
if (!r)
return 0;
if (r!=R_WOULDBLOCK) {
NR_SOCKET fd;
if (!nr_socket_getfd(tcpsock->inner, &fd)) {
NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_WRITE);
}
TAILQ_REMOVE(&sock->sockets, tcpsock, entry);
nr_tcp_socket_ctx_destroy(&tcpsock);
ABORT(r);
}
}
_status=R_WOULDBLOCK;
abort:
return(_status);
}
static int nr_socket_multi_tcp_getaddr(void *obj, nr_transport_addr *addrp)
{
nr_socket_multi_tcp *sock = (nr_socket_multi_tcp *)obj;
return nr_transport_addr_copy(addrp,&sock->addr);
}
static int nr_socket_multi_tcp_close(void *obj)
{
nr_socket_multi_tcp *sock = (nr_socket_multi_tcp *)obj;
nr_tcp_socket_ctx *tcpsock;
if(sock->listen_socket)
nr_socket_close(sock->listen_socket);
TAILQ_FOREACH(tcpsock, &sock->sockets, entry) {
nr_socket_close(tcpsock->inner); //ignore errors
}
return 0;
}
static void nr_tcp_socket_readable_cb(NR_SOCKET s, int how, void *arg)
{
nr_socket_multi_tcp *sock = (nr_socket_multi_tcp *)arg;
if (sock->readable_cb)
sock->readable_cb(s, how, sock->readable_cb_arg);
NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, nr_tcp_socket_readable_cb, arg);
}
static int nr_socket_multi_tcp_connect(void *obj, nr_transport_addr *addr)
{
int r, _status;
nr_socket_multi_tcp *sock = (nr_socket_multi_tcp *)obj;
nr_socket *nrsock;
if ((r=nr_socket_multi_tcp_get_sock_connected_to(sock,addr,PREALLOC_CONNECT_FRAMED,&nrsock)))
ABORT(r);
_status=0;
abort:
return(_status);
}
static void nr_tcp_multi_lsocket_readable_cb(NR_SOCKET s, int how, void *arg)
{
nr_socket_multi_tcp *sock = (nr_socket_multi_tcp *)arg;
nr_socket *newsock;
nr_transport_addr remote_addr;
nr_tcp_socket_ctx *tcp_sock_ctx;
int r;
//rearm
NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, nr_tcp_multi_lsocket_readable_cb, sock);
/* accept and add to socket_list */
if (nr_socket_accept(sock->listen_socket, &remote_addr, &newsock))
return;
/* This takes ownership of newsock whether it fails or not. */
if ((r=nr_tcp_socket_ctx_create(newsock, sock->use_framing, sock->max_pending, &tcp_sock_ctx)))
return;
nr_socket_buffered_set_connected_to(tcp_sock_ctx->inner, &remote_addr);
if (nr_tcp_socket_ctx_initialize(tcp_sock_ctx, &remote_addr, sock)) {
nr_tcp_socket_ctx_destroy(&tcp_sock_ctx);
return;
}
TAILQ_INSERT_HEAD(&sock->sockets, tcp_sock_ctx, entry);
}
static int nr_socket_multi_tcp_listen(void *obj, int backlog)
{
int r, _status;
nr_socket_multi_tcp *sock = (nr_socket_multi_tcp *)obj;
NR_SOCKET fd;
if(!sock->listen_socket)
ABORT(R_FAILED);
if ((r=nr_socket_listen(sock->listen_socket, backlog)))
ABORT(r);
if ((r=nr_socket_getfd(sock->listen_socket, &fd)))
ABORT(r);
NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, nr_tcp_multi_lsocket_readable_cb, sock);
_status=0;
abort:
return(_status);
}

View File

@ -0,0 +1,53 @@
/*
Copyright (c) 2007, Adobe Systems, Incorporated
Copyright (c) 2014, Mozilla
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Adobe Systems, Network Resonance nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _nr_socket_multi_tcp_h
#define _nr_socket_multi_tcp_h
#include "nr_socket.h"
/* Argument use_framing is 0 only in call from test code (STUN TCP server
listening socket). For other purposes it should be always set to true */
int nr_socket_multi_tcp_create(struct nr_ice_ctx_ *ctx,
nr_transport_addr *addr, nr_socket_tcp_type tcp_type,
int precreated_so_count, int use_framing, int max_pending,
nr_socket **sockp);
int nr_socket_multi_tcp_set_readable_cb(nr_socket *sock,
NR_async_cb readable_cb,void *readable_cb_arg);
int nr_socket_multi_tcp_stun_server_connect(nr_socket *sock,
nr_transport_addr *addr);
#endif

View File

@ -44,6 +44,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "stun.h"
#include "nr_socket_buffered_stun.h"
#define NR_MAX_FRAME_SIZE 0xFFFF
typedef struct nr_frame_header_ {
UINT2 frame_length;
char data[0];
} nr_frame_header;
typedef struct nr_socket_buffered_stun_ {
nr_socket *inner;
@ -65,6 +71,7 @@ typedef struct nr_socket_buffered_stun_ {
nr_p_buf_head pending_writes;
size_t pending;
size_t max_pending;
nr_framing_type framing_type;
} nr_socket_buffered_stun;
static int nr_socket_buffered_stun_destroy(void **objp);
@ -80,7 +87,7 @@ static int nr_socket_buffered_stun_write(void *obj,const void *msg, size_t len,
static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg);
static nr_socket_vtbl nr_socket_buffered_stun_vtbl={
1,
2,
nr_socket_buffered_stun_destroy,
nr_socket_buffered_stun_sendto,
nr_socket_buffered_stun_recvfrom,
@ -89,7 +96,9 @@ static nr_socket_vtbl nr_socket_buffered_stun_vtbl={
nr_socket_buffered_stun_connect,
0,
0,
nr_socket_buffered_stun_close
nr_socket_buffered_stun_close,
0,
0
};
int nr_socket_buffered_set_connected_to(nr_socket *sock, nr_transport_addr *remote_addr)
@ -107,33 +116,49 @@ abort:
return(_status);
}
int nr_socket_buffered_stun_create(nr_socket *inner, int max_pending, nr_socket **sockp)
int nr_socket_buffered_stun_create(nr_socket *inner, int max_pending,
nr_framing_type framing_type, nr_socket **sockp)
{
int r, _status;
nr_socket_buffered_stun *sock = 0;
size_t frame_size;
if (!(sock = RCALLOC(sizeof(nr_socket_buffered_stun))))
ABORT(R_NO_MEMORY);
sock->inner = inner;
sock->framing_type = framing_type;
if ((r=nr_ip4_port_to_transport_addr(INADDR_ANY, 0, IPPROTO_UDP, &sock->remote_addr)))
ABORT(r);
switch (framing_type) {
case ICE_TCP_FRAMING:
frame_size = sizeof(nr_frame_header);
sock->buffer_size = sizeof(nr_frame_header) + NR_MAX_FRAME_SIZE;
sock->bytes_needed = sizeof(nr_frame_header);
break;
case TURN_TCP_FRAMING:
frame_size = 0;
sock->buffer_size = NR_STUN_MAX_MESSAGE_SIZE;
sock->bytes_needed = sizeof(nr_stun_message_header);
break;
default:
assert(0);
ABORT(R_BAD_ARGS);
}
/* TODO(ekr@rtfm.com): Check this */
if (!(sock->buffer = RMALLOC(NR_STUN_MAX_MESSAGE_SIZE)))
if (!(sock->buffer = RMALLOC(sock->buffer_size)))
ABORT(R_NO_MEMORY);
sock->read_state = NR_ICE_SOCKET_READ_NONE;
sock->buffer_size = NR_STUN_MAX_MESSAGE_SIZE;
sock->bytes_needed = sizeof(nr_stun_message_header);
sock->connected = 0;
STAILQ_INIT(&sock->pending_writes);
if ((r=nr_p_buf_ctx_create(NR_STUN_MAX_MESSAGE_SIZE, &sock->p_bufs)))
if ((r=nr_p_buf_ctx_create(sock->buffer_size, &sock->p_bufs)))
ABORT(r);
sock->max_pending=max_pending;
sock->max_pending = max_pending + frame_size;
if ((r=nr_socket_create_int(sock, &nr_socket_buffered_stun_vtbl, sockp)))
ABORT(r);
@ -180,9 +205,9 @@ static int nr_socket_buffered_stun_sendto(void *obj,const void *msg, size_t len,
int flags, nr_transport_addr *to)
{
nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj;
int r, _status;
size_t written;
nr_frame_header *frame = NULL;
/* Check that we are writing to the connected address if
connected */
@ -193,6 +218,19 @@ static int nr_socket_buffered_stun_sendto(void *obj,const void *msg, size_t len,
}
}
if (sock->framing_type == ICE_TCP_FRAMING) {
assert(len <= NR_MAX_FRAME_SIZE);
if (len > NR_MAX_FRAME_SIZE)
ABORT(R_FAILED);
frame = RMALLOC(len + sizeof(nr_frame_header));
frame->frame_length = htons(len);
memcpy(frame->data, msg, len);
len += sizeof(nr_frame_header);
msg = frame;
}
if ((r=nr_socket_buffered_stun_write(obj, msg, len, &written)))
ABORT(r);
@ -201,6 +239,7 @@ static int nr_socket_buffered_stun_sendto(void *obj,const void *msg, size_t len,
_status=0;
abort:
RFREE(frame);
return _status;
}
@ -215,6 +254,8 @@ static int nr_socket_buffered_stun_recvfrom(void *obj,void * restrict buf,
int r, _status;
size_t bytes_read;
nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)obj;
nr_frame_header *frame = (nr_frame_header *)sock->buffer;
size_t skip_hdr_size = (sock->framing_type == ICE_TCP_FRAMING) ? sizeof(nr_frame_header) : 0;
if (sock->read_state == NR_ICE_SOCKET_READ_FAILED) {
ABORT(R_FAILED);
@ -237,38 +278,45 @@ reread:
if (sock->bytes_needed)
ABORT(R_WOULDBLOCK);
/* No more bytes expeected */
/* No more bytes expected */
if (sock->read_state == NR_ICE_SOCKET_READ_NONE) {
int tmp_length;
size_t remaining_length;
if (sock->framing_type == ICE_TCP_FRAMING) {
sock->bytes_needed = ntohs(frame->frame_length);
} else {
int tmp_length;
size_t remaining_length;
/* Parse the header */
if (r = nr_stun_message_length(sock->buffer, sock->bytes_read, &tmp_length))
ABORT(r);
assert(tmp_length >= 0);
if (tmp_length < 0)
ABORT(R_BAD_DATA);
remaining_length = tmp_length;
/* Parse the header */
if (r = nr_stun_message_length(sock->buffer, sock->bytes_read, &tmp_length))
ABORT(r);
assert(tmp_length >= 0);
if (tmp_length < 0)
ABORT(R_BAD_DATA);
remaining_length = tmp_length;
/* Check to see if we have enough room */
if ((sock->buffer_size - sock->bytes_read) < remaining_length)
ABORT(R_BAD_DATA);
/* Check to see if we have enough room */
if ((sock->buffer_size - sock->bytes_read) < remaining_length)
ABORT(R_BAD_DATA);
/* Set ourselves up to read the rest of the data */
/* Set ourselves up to read the rest of the data */
sock->bytes_needed = remaining_length;
}
sock->read_state = NR_ICE_SOCKET_READ_HDR;
sock->bytes_needed = remaining_length;
goto reread;
}
assert(skip_hdr_size <= sock->bytes_read);
sock->bytes_read -= skip_hdr_size;
if (maxlen < sock->bytes_read)
ABORT(R_BAD_ARGS);
memcpy(buf, sock->buffer, sock->bytes_read);
*len = sock->bytes_read;
sock->read_state = NR_ICE_SOCKET_READ_NONE;
memcpy(buf, sock->buffer + skip_hdr_size, sock->bytes_read);
sock->bytes_read = 0;
sock->bytes_needed = sizeof(nr_stun_message_header);
sock->read_state = NR_ICE_SOCKET_READ_NONE;
sock->bytes_needed = (sock->framing_type == ICE_TCP_FRAMING) ? sizeof(nr_frame_header) : sizeof(nr_stun_message_header);
assert(!nr_transport_addr_is_wildcard(&sock->remote_addr));
if (!nr_transport_addr_is_wildcard(&sock->remote_addr)) {
@ -441,6 +489,6 @@ static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg)
_status=0;
abort:
if (_status && _status != R_WOULDBLOCK) {
/* TODO(ekr@rtfm.com): Mark the socket as failed */
nr_socket_buffered_stun_failed(sock);
}
}

View File

@ -45,8 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This socket takes ownership of the inner socket |sock|.
*/
typedef enum {
TURN_TCP_FRAMING=0,
ICE_TCP_FRAMING
} nr_framing_type;
int nr_socket_buffered_stun_create(nr_socket *inner, int max_pending,
nr_socket **sockp);
nr_framing_type framing_type, nr_socket **sockp);
int nr_socket_buffered_set_connected_to(nr_socket *sock,
nr_transport_addr *remote_addr);

View File

@ -64,7 +64,7 @@ static int nr_socket_turn_getaddr(void *obj, nr_transport_addr *addrp);
static int nr_socket_turn_close(void *obj);
static nr_socket_vtbl nr_socket_turn_vtbl={
1,
2,
nr_socket_turn_destroy,
nr_socket_turn_sendto,
nr_socket_turn_recvfrom,
@ -73,7 +73,9 @@ static nr_socket_vtbl nr_socket_turn_vtbl={
0,
0,
0,
nr_socket_turn_close
nr_socket_turn_close,
0,
0
};
int nr_socket_turn_create(nr_socket *sock, nr_socket **sockp)

View File

@ -717,6 +717,12 @@ int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len
else
ABORT(R_BAD_DATA);
// STUN doesn't distinguish protocol in mapped address, therefore
// assign used protocol from peer_addr
if (mapped_addr->protocol!=peer_addr->protocol){
mapped_addr->protocol=peer_addr->protocol;
nr_transport_addr_fmt_addr_string(mapped_addr);
}
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received mapped address: %s", ctx->label, mapped_addr->as_string);
}

View File

@ -607,7 +607,8 @@ PeerConnectionImpl::AddIceServer(const RTCIceServer &aServer,
return NS_ERROR_FAILURE;
}
} else {
if (!aDst->addStunServer(host.get(), port)) {
if (!aDst->addStunServer(host.get(), port, (transport.IsEmpty() ?
kNrIceTransportUdp : transport.get()))) {
return NS_ERROR_FAILURE;
}
}

View File

@ -149,9 +149,10 @@ class PCUuidGenerator : public mozilla::JsepUuidGenerator {
class IceConfiguration
{
public:
bool addStunServer(const std::string& addr, uint16_t port)
bool addStunServer(const std::string& addr, uint16_t port,
const char* transport)
{
NrIceStunServer* server(NrIceStunServer::Create(addr, port));
NrIceStunServer* server(NrIceStunServer::Create(addr, port, transport));
if (!server) {
return false;
}

View File

@ -906,7 +906,8 @@ class SignalingAgent {
mExpectRtcpMuxAudio(true),
mExpectRtcpMuxVideo(true),
mRemoteDescriptionSet(false) {
cfg_.addStunServer(stun_addr, stun_port);
cfg_.addStunServer(stun_addr, stun_port, kNrIceTransportUdp);
cfg_.addStunServer(stun_addr, stun_port, kNrIceTransportTcp);
PeerConnectionImpl *pcImpl =
PeerConnectionImpl::CreatePeerConnection();