зеркало из https://github.com/mozilla/gecko-dev.git
Bug 846553: Use non-blocking connect() for SCTP DataChannelConnections, notify disconnects r=mcmanus
This commit is contained in:
Родитель
8a25067bd3
Коммит
b19879ed6d
|
@ -313,6 +313,15 @@ DataChannelConnection::Init(unsigned short aPort, uint16_t aNumStreams, bool aUs
|
|||
return false;
|
||||
}
|
||||
|
||||
// Make non-blocking for bind/connect. SCTP over UDP defaults to non-blocking
|
||||
// in associations for normal IO
|
||||
if (usrsctp_set_non_blocking(mMasterSocket, 1) < 0) {
|
||||
LOG(("Couldn't set non_blocking on SCTP socket"));
|
||||
// We can't handle connect() safely if it will block, not that this will
|
||||
// even happen.
|
||||
goto error_cleanup;
|
||||
}
|
||||
|
||||
// Make sure when we close the socket, make sure it doesn't call us back again!
|
||||
// This would cause it try to use an invalid DataChannelConnection pointer
|
||||
struct linger l;
|
||||
|
@ -321,18 +330,21 @@ DataChannelConnection::Init(unsigned short aPort, uint16_t aNumStreams, bool aUs
|
|||
if (usrsctp_setsockopt(mMasterSocket, SOL_SOCKET, SO_LINGER,
|
||||
(const void *)&l, (socklen_t)sizeof(struct linger)) < 0) {
|
||||
LOG(("Couldn't set SO_LINGER on SCTP socket"));
|
||||
// unsafe to allow it to continue if this fails
|
||||
goto error_cleanup;
|
||||
}
|
||||
|
||||
// XXX Consider disabling this when we add proper SDP negotiation.
|
||||
// We may want to leave enabled for supporting 'cloning' of SDP offers, which
|
||||
// implies re-use of the same pseudo-port number, or forcing a renegotiation.
|
||||
uint32_t on = 1;
|
||||
if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_REUSE_PORT,
|
||||
(const void *)&on, (socklen_t)sizeof(on)) < 0) {
|
||||
LOG(("Couldn't set SCTP_REUSE_PORT on SCTP socket"));
|
||||
{
|
||||
uint32_t on = 1;
|
||||
if (usrsctp_setsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_REUSE_PORT,
|
||||
(const void *)&on, (socklen_t)sizeof(on)) < 0) {
|
||||
LOG(("Couldn't set SCTP_REUSE_PORT on SCTP socket"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!aUsingDtls) {
|
||||
memset(&encaps, 0, sizeof(encaps));
|
||||
encaps.sue_address.ss_family = AF_INET;
|
||||
|
@ -453,60 +465,6 @@ DataChannelConnection::Notify(nsITimer *timer)
|
|||
}
|
||||
|
||||
#ifdef MOZ_PEERCONNECTION
|
||||
class DataChannelConnectRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
DataChannelConnectRunnable(DataChannelConnection *aConnection)
|
||||
: mConnection(aConnection) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
struct sockaddr_conn addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sconn_family = AF_CONN;
|
||||
#if defined(__Userspace_os_Darwin)
|
||||
addr.sconn_len = sizeof(addr);
|
||||
#endif
|
||||
addr.sconn_port = htons(mConnection->mLocalPort);
|
||||
|
||||
int r = usrsctp_bind(mConnection->mMasterSocket, reinterpret_cast<struct sockaddr *>(&addr),
|
||||
sizeof(addr));
|
||||
if (r < 0) {
|
||||
LOG(("usrsctp_bind failed: %d", r));
|
||||
} else {
|
||||
// This is the remote addr
|
||||
addr.sconn_port = htons(mConnection->mRemotePort);
|
||||
addr.sconn_addr = static_cast<void *>(mConnection.get());
|
||||
r = usrsctp_connect(mConnection->mMasterSocket, reinterpret_cast<struct sockaddr *>(&addr),
|
||||
sizeof(addr));
|
||||
if (r < 0) {
|
||||
LOG(("usrsctp_connect failed: %d", r));
|
||||
} else {
|
||||
// Notify Connection open
|
||||
LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, mConnection.get()));
|
||||
mConnection->mSocket = mConnection->mMasterSocket;
|
||||
mConnection->mState = DataChannelConnection::OPEN;
|
||||
LOG(("DTLS connect() succeeded! Entering connected mode"));
|
||||
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
mConnection, true));
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// on errors, we simply don't notify there was a connection, but we
|
||||
// want to kill the thread (can we kill ourselves here? That would be better)
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
mConnection, false));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<DataChannelConnection> mConnection;
|
||||
};
|
||||
|
||||
bool
|
||||
DataChannelConnection::ConnectDTLS(TransportFlow *aFlow, uint16_t localport, uint16_t remoteport)
|
||||
{
|
||||
|
@ -519,11 +477,54 @@ DataChannelConnection::ConnectDTLS(TransportFlow *aFlow, uint16_t localport, uin
|
|||
mTransportFlow->SignalPacketReceived.connect(this, &DataChannelConnection::SctpDtlsInput);
|
||||
mLocalPort = localport;
|
||||
mRemotePort = remoteport;
|
||||
mState = CONNECTING;
|
||||
|
||||
nsCOMPtr<nsIRunnable> connect_event = new DataChannelConnectRunnable(this);
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(mConnectThread), connect_event);
|
||||
struct sockaddr_conn addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sconn_family = AF_CONN;
|
||||
#if defined(__Userspace_os_Darwin)
|
||||
addr.sconn_len = sizeof(addr);
|
||||
#endif
|
||||
addr.sconn_port = htons(mLocalPort);
|
||||
|
||||
return NS_SUCCEEDED(rv);
|
||||
LOG(("Calling usrsctp_bind"));
|
||||
int r = usrsctp_bind(mMasterSocket, reinterpret_cast<struct sockaddr *>(&addr),
|
||||
sizeof(addr));
|
||||
if (r < 0) {
|
||||
LOG(("usrsctp_bind failed: %d", r));
|
||||
} else {
|
||||
// This is the remote addr
|
||||
addr.sconn_port = htons(mRemotePort);
|
||||
addr.sconn_addr = static_cast<void *>(this);
|
||||
LOG(("Calling usrsctp_connect"));
|
||||
r = usrsctp_connect(mMasterSocket, reinterpret_cast<struct sockaddr *>(&addr),
|
||||
sizeof(addr));
|
||||
if (r < 0) {
|
||||
if (errno == EINPROGRESS) {
|
||||
// non-blocking
|
||||
return true;
|
||||
} else {
|
||||
LOG(("usrsctp_connect failed: %d", errno));
|
||||
mState = CLOSED;
|
||||
}
|
||||
} else {
|
||||
// Notify Connection open
|
||||
LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this));
|
||||
mSocket = mMasterSocket;
|
||||
mState = OPEN;
|
||||
LOG(("DTLS connect() succeeded! Entering connected mode"));
|
||||
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
this, true));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Note: currently this doesn't actually notify the application
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
this, false));
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1340,15 +1341,34 @@ DataChannelConnection::HandleAssociationChangeEvent(const struct sctp_assoc_chan
|
|||
switch (sac->sac_state) {
|
||||
case SCTP_COMM_UP:
|
||||
LOG(("Association change: SCTP_COMM_UP"));
|
||||
if (mState == CONNECTING) {
|
||||
mSocket = mMasterSocket;
|
||||
mState = OPEN;
|
||||
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
this, true));
|
||||
LOG(("DTLS connect() succeeded! Entering connected mode"));
|
||||
} else if (mState == OPEN) {
|
||||
LOG(("DataConnection Already OPEN"));
|
||||
} else {
|
||||
LOG(("Unexpected state: %d", mState));
|
||||
}
|
||||
break;
|
||||
case SCTP_COMM_LOST:
|
||||
LOG(("Association change: SCTP_COMM_LOST"));
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_DISCONNECTED,
|
||||
this));
|
||||
break;
|
||||
case SCTP_RESTART:
|
||||
LOG(("Association change: SCTP_RESTART"));
|
||||
break;
|
||||
case SCTP_SHUTDOWN_COMP:
|
||||
LOG(("Association change: SCTP_SHUTDOWN_COMP"));
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_DISCONNECTED,
|
||||
this));
|
||||
break;
|
||||
case SCTP_CANT_STR_ASSOC:
|
||||
LOG(("Association change: SCTP_CANT_STR_ASSOC"));
|
||||
|
|
|
@ -265,9 +265,6 @@ private:
|
|||
nsCOMPtr<nsITimer> mDeferredTimer;
|
||||
uint32_t mDeferTimeout; // in ms
|
||||
bool mTimerRunning;
|
||||
|
||||
// Thread used for connections
|
||||
nsCOMPtr<nsIThread> mConnectThread;
|
||||
};
|
||||
|
||||
#define ENSURE_DATACONNECTION \
|
||||
|
@ -445,10 +442,10 @@ public:
|
|||
mChannel(aChannel),
|
||||
mConnection(aConnection) {}
|
||||
|
||||
// for ON_CONNECTION
|
||||
// for ON_CONNECTION/ON_DISCONNECTED
|
||||
DataChannelOnMessageAvailable(int32_t aType,
|
||||
DataChannelConnection *aConnection,
|
||||
bool aResult)
|
||||
bool aResult = true)
|
||||
: mType(aType),
|
||||
mConnection(aConnection),
|
||||
mResult(aResult) {}
|
||||
|
@ -501,7 +498,7 @@ public:
|
|||
if (mResult) {
|
||||
mConnection->mListener->NotifyConnection();
|
||||
}
|
||||
mConnection->mConnectThread = nullptr; // kill the connection thread
|
||||
// FIX - on mResult false (failure) we should do something. Needs spec work here
|
||||
break;
|
||||
case ON_DISCONNECTED:
|
||||
mConnection->mListener->NotifyClosedConnection();
|
||||
|
|
Загрузка…
Ссылка в новой задаче