mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 891551 - Part 5: Add support for TCP ICE candidates. r=bwc,jesup
This commit is contained in:
parent
aec584b5a8
commit
6d354a80da
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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_.
|
||||
|
@ -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_);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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',
|
||||
|
401
media/mtransport/test/multi_tcp_socket_unittest.cpp
Normal file
401
media/mtransport/test/multi_tcp_socket_unittest.cpp
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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_;
|
||||
|
2
media/mtransport/third_party/nICEr/nicer.gyp
vendored
2
media/mtransport/third_party/nICEr/nicer.gyp
vendored
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
565
media/mtransport/third_party/nICEr/src/net/nr_socket_multi_tcp.c
vendored
Normal file
565
media/mtransport/third_party/nICEr/src/net/nr_socket_multi_tcp.c
vendored
Normal 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);
|
||||
}
|
53
media/mtransport/third_party/nICEr/src/net/nr_socket_multi_tcp.h
vendored
Normal file
53
media/mtransport/third_party/nICEr/src/net/nr_socket_multi_tcp.h
vendored
Normal 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
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user