diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index 55417fe2cc95..1038f4fb3a83 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -480,15 +480,10 @@ PeerConnectionImpl::ConnectDataConnection(uint16_t aLocalport, return NS_ERROR_FAILURE; } // XXX Fix! Get the correct flow for DataChannel. Also error handling. - for (int i = 2; i >= 0; i--) { - nsRefPtr flow = mMedia->GetTransportFlow(i,false).get(); - CSFLogDebugS(logTag, "Transportflow[" << i << "] = " << flow.get()); - if (flow) { - if (!mDataConnection->ConnectDTLS(flow, aLocalport, aRemoteport)) { - return NS_ERROR_FAILURE; - } - break; - } + nsRefPtr flow = mMedia->GetTransportFlow(1,false).get(); + CSFLogDebugS(logTag, "Transportflow[1] = " << flow.get()); + if (!mDataConnection->ConnectDTLS(flow, aLocalport, aRemoteport)) { + return NS_ERROR_FAILURE; } return NS_OK; #else @@ -925,7 +920,6 @@ PeerConnectionImpl::CheckApiState(bool assert_ice_ready) const NS_IMETHODIMP PeerConnectionImpl::Close(bool aIsSynchronous) { - CSFLogDebugS(logTag, __FUNCTION__); PC_AUTO_ENTER_API_CALL(false); return CloseInt(aIsSynchronous); @@ -940,10 +934,8 @@ PeerConnectionImpl::CloseInt(bool aIsSynchronous) if (mCall != nullptr) mCall->endCall(); #ifdef MOZILLA_INTERNAL_API - if (mDataConnection) { - mDataConnection->Destroy(); - mDataConnection = nullptr; // it may not go away until the runnables are dead - } + if (mDataConnection) + mDataConnection->CloseAll(); #endif ShutdownMedia(aIsSynchronous); diff --git a/netwerk/sctp/datachannel/DataChannel.cpp b/netwerk/sctp/datachannel/DataChannel.cpp index 1c4643feb601..0e1eca56e7cc 100644 --- a/netwerk/sctp/datachannel/DataChannel.cpp +++ b/netwerk/sctp/datachannel/DataChannel.cpp @@ -46,7 +46,7 @@ static bool sctp_initialized; namespace mozilla { class DataChannelShutdown; -nsRefPtr gDataChannelShutdown; +nsCOMPtr gDataChannelShutdown; class DataChannelShutdown : public nsIObserver { @@ -61,7 +61,7 @@ public: DataChannelShutdown() {} - void Init() + void Init() { nsCOMPtr observerService = mozilla::services::GetObserverService(); @@ -91,18 +91,6 @@ public: usrsctp_finish(); sctp_initialized = false; } - nsCOMPtr observerService = - mozilla::services::GetObserverService(); - if (!observerService) - return NS_ERROR_FAILURE; - - nsresult rv = observerService->RemoveObserver(this, - "profile-change-net-teardown"); - MOZ_ASSERT(rv == NS_OK); - (void) rv; - - nsRefPtr kungFuDeathGrip(this); - gDataChannelShutdown = nullptr; } return NS_OK; } @@ -152,31 +140,17 @@ DataChannelConnection::DataChannelConnection(DataConnectionListener *listener) : DataChannelConnection::~DataChannelConnection() { - // This may die on the MainThread, or on the STS thread - MOZ_ASSERT(mState == CLOSED); - MOZ_ASSERT(!mMasterSocket); -} - -void -DataChannelConnection::Destroy() -{ + // XXX Move CloseAll() to a Destroy() call // Though it's probably ok to do this and close the sockets; // if we really want it to do true clean shutdowns it can // create a dependant Internal object that would remain around // until the network shut down the association or timed out. - LOG(("Destroying DataChannelConnection %p", (void *) this)); + LOG(("Destroying DataChannelConnection")); CloseAll(); - if (mSocket && mSocket != mMasterSocket) usrsctp_close(mSocket); if (mMasterSocket) usrsctp_close(mMasterSocket); - - mSocket = nullptr; - mMasterSocket = nullptr; - - // We can't get any more new callbacks from the SCTP library - // All existing callbacks have refs to DataChannelConnection } NS_IMPL_THREADSAFE_ISUPPORTS1(DataChannelConnection, @@ -216,10 +190,7 @@ DataChannelConnection::Init(unsigned short aPort, uint16_t aNumStreams, bool aUs usrsctp_init(aPort, nullptr); } - // Set logging to datachannel:6 to get SCTP debugs -#ifdef PR_LOGGING - usrsctp_sysctl_set_sctp_debug_on(GetDataChannelLog()->level > 5 ? SCTP_DEBUG_ALL : 0); -#endif + usrsctp_sysctl_set_sctp_debug_on(0 /* SCTP_DEBUG_ALL */); usrsctp_sysctl_set_sctp_blackhole(2); sctp_initialized = true; @@ -227,14 +198,14 @@ DataChannelConnection::Init(unsigned short aPort, uint16_t aNumStreams, bool aUs gDataChannelShutdown->Init(); } } - // XXX FIX! make this a global we get once // Find the STS thread - nsresult rv; - mSTS = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - // Open sctp with a callback + nsresult res; + mSTS = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &res); + MOZ_ASSERT(NS_SUCCEEDED(res)); + + // Open sctp association across tunnel if ((mMasterSocket = usrsctp_socket( aUsingDtls ? AF_CONN : AF_INET, SOCK_STREAM, IPPROTO_SCTP, receive_cb, nullptr, 0, this)) == nullptr) { @@ -251,16 +222,6 @@ DataChannelConnection::Init(unsigned short aPort, uint16_t aNumStreams, bool aUs LOG(("Couldn't set SO_LINGER on SCTP socket")); } - // 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")); - } - - if (!aUsingDtls) { memset(&encaps, 0, sizeof(encaps)); encaps.sue_address.ss_family = AF_INET; @@ -381,60 +342,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_Linux) && !defined(__Userspace_os_Windows) - addr.sconn_len = sizeof(addr); -#endif - addr.sconn_port = htons(mConnection->mLocalPort); - - int r = usrsctp_bind(mConnection->mMasterSocket, reinterpret_cast(&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(mConnection.get()); - r = usrsctp_connect(mConnection->mMasterSocket, reinterpret_cast(&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 mConnection; -}; - bool DataChannelConnection::ConnectDTLS(TransportFlow *aFlow, uint16_t localport, uint16_t remoteport) { @@ -448,10 +355,57 @@ DataChannelConnection::ConnectDTLS(TransportFlow *aFlow, uint16_t localport, uin mLocalPort = localport; mRemotePort = remoteport; - nsCOMPtr connect_event = new DataChannelConnectRunnable(this); - nsresult rv = NS_NewThread(getter_AddRefs(mConnectThread), connect_event); + PR_CreateThread( + PR_SYSTEM_THREAD, + DataChannelConnection::DTLSConnectThread, this, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, 0 + ); - return NS_SUCCEEDED(rv); + return true; // not finished yet +} + +/* static */ +void +DataChannelConnection::DTLSConnectThread(void *data) +{ + DataChannelConnection *_this = static_cast(data); + 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(_this->mLocalPort); + + int r = usrsctp_bind(_this->mMasterSocket, reinterpret_cast(&addr), + sizeof(addr)); + if (r < 0) { + LOG(("usrsctp_bind failed: %d", r)); + return; + } + + // This is the remote addr + addr.sconn_port = htons(_this->mRemotePort); + addr.sconn_addr = static_cast(_this); + r = usrsctp_connect(_this->mMasterSocket, reinterpret_cast(&addr), + sizeof(addr)); + if (r < 0) { + LOG(("usrsctp_connect failed: %d", r)); + return; + } + + // Notify Connection open + LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, _this)); + _this->mSocket = _this->mMasterSocket; + _this->mState = OPEN; + LOG(("DTLS connect() succeeded! Entering connected mode")); + + NS_DispatchToMainThread(new DataChannelOnMessageAvailable( + DataChannelOnMessageAvailable::ON_CONNECTION, + _this, nullptr)); } void @@ -498,9 +452,8 @@ DataChannelConnection::SctpDtlsOutput(void *addr, void *buffer, size_t length, // DISPATCH_SYNC is not fully blocking. This may be tricky, as it // needs to be a per-thread check, not a global. peer->mSTS->Dispatch(WrapRunnable( - nsRefPtr(peer), - &DataChannelConnection::SendPacket, data, length, true), - NS_DISPATCH_NORMAL); + peer, &DataChannelConnection::SendPacket, data, length, true + ), NS_DISPATCH_NORMAL); res = 0; // cheat! Packets can always be dropped later anyways } return res; @@ -1023,7 +976,7 @@ DataChannelConnection::OpenResponseFinish(already_AddRefed aChannel if (SendOpenResponseMessage(streamOut, channel->mStreamIn)) { /* Notify ondatachannel */ // XXX We need to make sure connection sticks around until the message is delivered - LOG(("%s: sending ON_CHANNEL_CREATED for %s: %d/%d", __FUNCTION__, + LOG(("%s: sending ON_CHANNEL_CREATED for %s: %d/%d", __FUNCTION__, channel->mLabel.get(), streamOut, channel->mStreamIn)); NS_DispatchToMainThread(new DataChannelOnMessageAvailable( DataChannelOnMessageAvailable::ON_CHANNEL_CREATED, @@ -1440,8 +1393,7 @@ DataChannelConnection::ResetOutgoingStream(uint16_t streamOut) uint32_t i; mLock.AssertCurrentThreadOwns(); - LOG(("Connection %p: Resetting outgoing stream %d", - (void *) this, streamOut)); + LOG(("Resetting outgoing stream %d",streamOut)); // Rarely has more than a couple items and only for a short time for (i = 0; i < mStreamsResetting.Length(); ++i) { if (mStreamsResetting[i] == streamOut) { @@ -1458,11 +1410,8 @@ DataChannelConnection::SendOutgoingStreamReset() uint32_t i; size_t len; - LOG(("Connection %p: Sending outgoing stream reset for %d streams", - (void *) this, mStreamsResetting.Length())); mLock.AssertCurrentThreadOwns(); - if (mStreamsResetting.IsEmpty()) { - LOG(("No streams to reset")); + if (mStreamsResetting.IsEmpty() == 0) { return; } len = sizeof(sctp_assoc_t) + (2 + mStreamsResetting.Length()) * sizeof(uint16_t); @@ -1494,57 +1443,40 @@ DataChannelConnection::HandleStreamResetEvent(const struct sctp_stream_reset_eve if (strrst->strreset_flags & SCTP_STREAM_RESET_INCOMING_SSN) { channel = FindChannelByStreamIn(strrst->strreset_stream_list[i]); if (channel) { - // The other side closed the channel - // We could be in three states: - // 1. Normal state (input and output streams (OPEN) - // Notify application, send a RESET in response on our - // outbound channel. Go to CLOSED - // 2. We sent our own reset (CLOSING); either they crossed on the - // wire, or this is a response to our Reset. - // Go to CLOSED - // 3. We've sent a open but haven't gotten a response yet (OPENING) - // I believe this is impossible, as we don't have an input stream yet. - - LOG(("Incoming: Channel %d outgoing/%d incoming closed, state %d", - channel->mStreamOut, channel->mStreamIn, channel->mState)); - MOZ_ASSERT(channel->mState == OPEN || channel->mState == CLOSING); - if (channel->mState == OPEN) { - ResetOutgoingStream(channel->mStreamOut); + LOG(("Channel %d outgoing/%d incoming closed", + channel->mStreamOut,channel->mStreamIn)); + mStreamsIn[channel->mStreamIn] = nullptr; + channel->mStreamIn = INVALID_STREAM; + if (channel->mStreamOut == INVALID_STREAM) { + channel->mPrPolicy = SCTP_PR_SCTP_NONE; + channel->mPrValue = 0; + channel->mFlags = 0; + channel->mState = CLOSED; NS_DispatchToMainThread(new DataChannelOnMessageAvailable( DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this, channel)); - mStreamsOut[channel->mStreamOut] = nullptr; + } else { + ResetOutgoingStream(channel->mStreamOut); + channel->mState = CLOSING; } - mStreamsIn[channel->mStreamIn] = nullptr; - - LOG(("Disconnected DataChannel %p from connection %p", - (void *) channel.get(), (void *) channel->mConnection.get())); - channel->Destroy(); - // At this point when we leave here, the object is a zombie held alive only by the DOM object - } else { - LOG(("Can't find incoming channel %d",i)); } } - if (strrst->strreset_flags & SCTP_STREAM_RESET_OUTGOING_SSN) { channel = FindChannelByStreamOut(strrst->strreset_stream_list[i]); - if (channel) { - LOG(("Outgoing: Connection %p channel %p streams: %d outgoing/%d incoming closed", - (void *) this, (void *) channel.get(), channel->mStreamOut, channel->mStreamIn)); - - MOZ_ASSERT(channel->mState == CLOSING); - if (channel->mState == CLOSING) { - mStreamsOut[channel->mStreamOut] = nullptr; - if (channel->mStreamIn != INVALID_STREAM) - mStreamsIn[channel->mStreamIn] = nullptr; - LOG(("Disconnected DataChannel %p from connection %p (refcnt will be %u)", - (void *) channel.get(), (void *) channel->mConnection.get(), - (uint32_t) channel->mConnection->mRefCnt-1)); - channel->Destroy(); - // At this point when we leave here, the object is a zombie held alive only by the DOM object + if (channel != nullptr && channel->mStreamOut != INVALID_STREAM) { + LOG(("Channel %d outgoing/%d incoming closed", + channel->mStreamOut,channel->mStreamIn)); + mStreamsOut[channel->mStreamOut] = nullptr; + channel->mStreamOut = INVALID_STREAM; + if (channel->mStreamIn == INVALID_STREAM) { + channel->mPrPolicy = SCTP_PR_SCTP_NONE; + channel->mPrValue = 0; + channel->mFlags = 0; + channel->mState = CLOSED; + NS_DispatchToMainThread(new DataChannelOnMessageAvailable( + DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this, + channel)); } - } else { - LOG(("Can't find outgoing channel %d",i)); } } } @@ -1759,7 +1691,7 @@ DataChannelConnection::Open(const nsACString& label, Type type, bool inOrder, } flags = !inOrder ? DATA_CHANNEL_FLAG_OUT_OF_ORDER_ALLOWED : 0; - nsRefPtr channel(new DataChannel(this, + nsRefPtr channel(new DataChannel(this, INVALID_STREAM, INVALID_STREAM, DataChannel::CONNECTING, label, type, prValue, @@ -2006,17 +1938,14 @@ DataChannelConnection::Close(uint16_t streamOut) nsRefPtr channel; // make sure it doesn't go away on us MutexAutoLock lock(mLock); + LOG(("Closing stream %d",streamOut)); channel = FindChannelByStreamOut(streamOut); if (channel) { - LOG(("Connection %p/Channel %p: Closing stream %d", - (void *) channel->mConnection.get(), (void *) channel.get(), streamOut)); channel->mBufferedData.Clear(); if (channel->mStreamOut != INVALID_STREAM) ResetOutgoingStream(channel->mStreamOut); SendOutgoingStreamReset(); channel->mState = CLOSING; - } else { - LOG(("!!!? no channel when closing stream %d?",streamOut)); } } @@ -2029,8 +1958,8 @@ void DataChannelConnection::CloseAll() mState = CLOSED; // Close current channels - // If there are runnables, they hold a strong ref and keep the channel - // and/or connection alive (even if in a CLOSED state) + // FIX! if there are runnables, they must use weakrefs or hold a strong + // ref and keep the channel and/or connection alive for (uint32_t i = 0; i < mStreamsOut.Length(); ++i) { if (mStreamsOut[i]) { mStreamsOut[i]->Close(); @@ -2044,35 +1973,22 @@ void DataChannelConnection::CloseAll() } DataChannel::~DataChannel() -{ - if (mConnection) - Close(); -} - -// Used when disconnecting from the DataChannelConnection -void -DataChannel::Destroy() { LOG(("Destroying Data channel %d/%d", mStreamOut, mStreamIn)); - MOZ_ASSERT_IF(mStreamOut != INVALID_STREAM, - !mConnection->FindChannelByStreamOut(mStreamOut)); - MOZ_ASSERT_IF(mStreamIn != INVALID_STREAM, - !mConnection->FindChannelByStreamIn(mStreamIn)); - mStreamIn = INVALID_STREAM; - mStreamOut = INVALID_STREAM; - mState = CLOSED; - mConnection = nullptr; + Close(); } void DataChannel::Close() -{ +{ if (mState == CLOSING || mState == CLOSED || mStreamOut == INVALID_STREAM) { return; } mState = CLOSING; mConnection->Close(mStreamOut); + mStreamOut = INVALID_STREAM; + mStreamIn = INVALID_STREAM; } void @@ -2120,3 +2036,4 @@ DataChannel::GetBufferedAmount() } } // namespace mozilla + diff --git a/netwerk/sctp/datachannel/DataChannel.h b/netwerk/sctp/datachannel/DataChannel.h index 790159965acd..c03d918e492b 100644 --- a/netwerk/sctp/datachannel/DataChannel.h +++ b/netwerk/sctp/datachannel/DataChannel.h @@ -109,7 +109,6 @@ public: virtual ~DataChannelConnection(); bool Init(unsigned short aPort, uint16_t aNumStreams, bool aUsingDtls); - void Destroy(); // So we can spawn refs tied to runnables in shutdown // These block; they require something to decide on listener/connector // (though you can do simultaneous Connect()). Do not call these from @@ -169,8 +168,6 @@ protected: DataConnectionListener *mListener; private: - friend class DataChannelConnectRunnable; - #ifdef SCTP_DTLS_SUPPORTED static void DTLSConnectThread(void *data); int SendPacket(const unsigned char* data, size_t len, bool release); @@ -238,24 +235,21 @@ private: // Streams pending reset nsAutoTArray mStreamsResetting; - struct socket *mMasterSocket; // accessed from connect thread - struct socket *mSocket; // cloned from mMasterSocket on successful Connect on connect thread - uint16_t mState; // modified on connect thread (to OPEN) + struct socket *mMasterSocket; + struct socket *mSocket; + uint16_t mState; #ifdef SCTP_DTLS_SUPPORTED nsRefPtr mTransportFlow; nsCOMPtr mSTS; #endif - uint16_t mLocalPort; // Accessed from connect thread + uint16_t mLocalPort; uint16_t mRemotePort; // Timer to control when we try to resend blocked messages nsCOMPtr mDeferredTimer; uint32_t mDeferTimeout; // in ms bool mTimerRunning; - - // Thread used for connections - nsCOMPtr mConnectThread; }; class DataChannel { @@ -292,7 +286,6 @@ public: } ~DataChannel(); - void Destroy(); // when we disconnect from the connection after stream RESET NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataChannel) @@ -420,14 +413,6 @@ public: mChannel(aChannel), mConnection(aConnection) {} - // for ON_CONNECTION - DataChannelOnMessageAvailable(int32_t aType, - DataChannelConnection *aConnection, - bool aResult) - : mType(aType), - mConnection(aConnection), - mResult(aResult) {} - NS_IMETHOD Run() { switch (mType) { @@ -464,10 +449,7 @@ public: mConnection->mListener->NotifyDataChannel(mChannel); break; case ON_CONNECTION: - if (mResult) { - mConnection->mListener->NotifyConnection(); - } - mConnection->mConnectThread = nullptr; // kill the connection thread + mConnection->mListener->NotifyConnection(); break; case ON_DISCONNECTED: mConnection->mListener->NotifyClosedConnection(); @@ -488,7 +470,6 @@ private: nsRefPtr mConnection; nsCString mData; int32_t mLen; - bool mResult; }; }