Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 8472648

Browse files
committed
Bug 855623: Add 'protocol' field, and support external negotiation r=tuexen,ehugg
1 parent 494d095 commit 8472648

4 files changed

Lines changed: 142 additions & 76 deletions

File tree

media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -679,10 +679,13 @@ PeerConnectionImpl::InitializeDataChannel(uint16_t aLocalport,
679679

680680
NS_IMETHODIMP
681681
PeerConnectionImpl::CreateDataChannel(const nsACString& aLabel,
682+
const nsACString& aProtocol,
682683
uint16_t aType,
683684
bool outOfOrderAllowed,
684685
uint16_t aMaxTime,
685686
uint16_t aMaxNum,
687+
bool aExternalNegotiated,
688+
uint16_t aStream,
686689
nsIDOMDataChannel** aRetval)
687690
{
688691
PC_AUTO_ENTER_API_CALL_NO_CHECK();
@@ -697,10 +700,10 @@ PeerConnectionImpl::CreateDataChannel(const nsACString& aLabel,
697700
return NS_ERROR_FAILURE;
698701
}
699702
dataChannel = mDataConnection->Open(
700-
aLabel, theType, !outOfOrderAllowed,
703+
aLabel, aProtocol, theType, !outOfOrderAllowed,
701704
aType == mozilla::DataChannelConnection::PARTIAL_RELIABLE_REXMIT ? aMaxNum :
702705
(aType == mozilla::DataChannelConnection::PARTIAL_RELIABLE_TIMED ? aMaxTime : 0),
703-
nullptr, nullptr
706+
nullptr, nullptr, aExternalNegotiated, aStream
704707
);
705708
NS_ENSURE_TRUE(dataChannel,NS_ERROR_FAILURE);
706709

netwerk/sctp/datachannel/DataChannel.cpp

Lines changed: 122 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -838,12 +838,14 @@ DataChannelConnection::SendControlMessage(void *msg, uint32_t len, uint16_t stre
838838

839839
int32_t
840840
DataChannelConnection::SendOpenRequestMessage(const nsACString& label,
841+
const nsACString& protocol,
841842
uint16_t stream, bool unordered,
842843
uint16_t prPolicy, uint32_t prValue)
843844
{
844-
int len = label.Length(); // not including nul
845+
int label_len = label.Length(); // not including nul
846+
int proto_len = protocol.Length(); // not including nul
845847
struct rtcweb_datachannel_open_request *req =
846-
(struct rtcweb_datachannel_open_request*) moz_xmalloc(sizeof(*req)+len);
848+
(struct rtcweb_datachannel_open_request*) moz_xmalloc(sizeof(*req)+label_len+proto_len+1);
847849
// careful - ok because request includes 1 char label
848850

849851
memset(req, 0, sizeof(struct rtcweb_datachannel_open_request));
@@ -869,9 +871,13 @@ DataChannelConnection::SendOpenRequestMessage(const nsACString& label,
869871
}
870872
req->reliability_params = htons((uint16_t)prValue); /* XXX Why 16-bit */
871873
req->priority = htons(0); /* XXX: add support */
874+
req->label_length = label_len;
875+
req->protocol_length = proto_len;
872876
strcpy(&req->label[0], PromiseFlatCString(label).get());
877+
strcpy(&req->label[req->label_length+1], PromiseFlatCString(protocol).get());
873878

874-
int32_t result = SendControlMessage(req, sizeof(*req)+len, stream);
879+
// sizeof(*req) already includes +1 byte for label, need nul for both strings
880+
int32_t result = SendControlMessage(req, sizeof(*req)+label_len+proto_len+1, stream);
875881

876882
moz_free(req);
877883
return result;
@@ -907,7 +913,8 @@ DataChannelConnection::SendDeferredMessages()
907913

908914
// Only one of these should be set....
909915
if (channel->mFlags & DATA_CHANNEL_FLAGS_SEND_REQ) {
910-
if (SendOpenRequestMessage(channel->mLabel, channel->mStream,
916+
if (SendOpenRequestMessage(channel->mLabel, channel->mProtocol,
917+
channel->mStream,
911918
channel->mFlags & DATA_CHANNEL_FLAG_OUT_OF_ORDER_ALLOWED,
912919
channel->mPrPolicy, channel->mPrValue)) {
913920
channel->mFlags &= ~DATA_CHANNEL_FLAGS_SEND_REQ;
@@ -996,15 +1003,10 @@ DataChannelConnection::HandleOpenRequestMessage(const struct rtcweb_datachannel_
9961003
uint16_t prPolicy;
9971004
uint32_t flags;
9981005
nsCString label(nsDependentCString(req->label));
1006+
nsCString protocol(nsDependentCString(&req->label[req->label_length+1]));
9991007

10001008
mLock.AssertCurrentThreadOwns();
10011009

1002-
if ((channel = FindChannelByStream(stream))) {
1003-
LOG(("ERROR: HandleOpenRequestMessage: channel for stream %u is in state %d instead of CLOSED.",
1004-
stream, channel->mState));
1005-
/* XXX: some error handling */
1006-
return;
1007-
}
10081010
switch (req->channel_type) {
10091011
case DATA_CHANNEL_RELIABLE:
10101012
prPolicy = SCTP_PR_SCTP_NONE;
@@ -1021,19 +1023,41 @@ DataChannelConnection::HandleOpenRequestMessage(const struct rtcweb_datachannel_
10211023
}
10221024
prValue = ntohs(req->reliability_params);
10231025
flags = ntohs(req->flags) & DATA_CHANNEL_FLAG_OUT_OF_ORDER_ALLOWED;
1026+
1027+
if ((channel = FindChannelByStream(stream))) {
1028+
if (!(channel->mFlags & DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED)) {
1029+
LOG(("ERROR: HandleOpenRequestMessage: channel for stream %u is in state %d instead of CLOSED.",
1030+
stream, channel->mState));
1031+
/* XXX: some error handling */
1032+
} else {
1033+
LOG(("Open for externally negotiated channel %u", stream));
1034+
// XXX should also check protocol, maybe label
1035+
if (prPolicy != channel->mPrPolicy ||
1036+
prValue != channel->mPrValue ||
1037+
flags != (channel->mFlags & DATA_CHANNEL_FLAG_OUT_OF_ORDER_ALLOWED))
1038+
{
1039+
LOG(("WARNING: external negotiation mismatch with OpenRequest:"
1040+
"channel %u, policy %u/%u, value %u/%u, flags %x/%x",
1041+
stream, prPolicy, channel->mPrPolicy,
1042+
prValue, channel->mPrValue, flags, channel->mFlags));
1043+
}
1044+
}
1045+
return;
1046+
}
10241047
channel = new DataChannel(this,
10251048
stream,
10261049
DataChannel::CONNECTING,
10271050
label,
1051+
protocol,
10281052
prPolicy, prValue,
10291053
flags,
10301054
nullptr, nullptr);
10311055
mStreams[stream] = channel;
10321056

10331057
channel->mState = DataChannel::WAITING_TO_OPEN;
10341058

1035-
LOG(("%s: sending ON_CHANNEL_CREATED for %s: %u", __FUNCTION__,
1036-
channel->mLabel.get(), stream));
1059+
LOG(("%s: sending ON_CHANNEL_CREATED for %s/%s: %u", __FUNCTION__,
1060+
channel->mLabel.get(), channel->mProtocol.get(), stream));
10371061
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
10381062
DataChannelOnMessageAvailable::ON_CHANNEL_CREATED,
10391063
this, channel));
@@ -1691,15 +1715,20 @@ DataChannelConnection::ReceiveCallback(struct socket* sock, void *data, size_t d
16911715
}
16921716

16931717
already_AddRefed<DataChannel>
1694-
DataChannelConnection::Open(const nsACString& label, Type type, bool inOrder,
1718+
DataChannelConnection::Open(const nsACString& label, const nsACString& protocol,
1719+
Type type, bool inOrder,
16951720
uint32_t prValue, DataChannelListener *aListener,
1696-
nsISupports *aContext)
1721+
nsISupports *aContext, bool aExternalNegotiated,
1722+
uint16_t aStream)
16971723
{
1724+
// aStream == INVALID_STREAM to have the protocol allocate
16981725
uint16_t prPolicy = SCTP_PR_SCTP_NONE;
16991726
uint32_t flags;
17001727

1701-
LOG(("DC Open: label %s, type %u, inorder %d, prValue %u, listener %p, context %p",
1702-
PromiseFlatCString(label).get(), type, inOrder, prValue, aListener, aContext));
1728+
LOG(("DC Open: label %s/%s, type %u, inorder %d, prValue %u, listener %p, context %p, external: %s, stream %u",
1729+
PromiseFlatCString(label).get(), PromiseFlatCString(protocol).get(),
1730+
type, inOrder, prValue, aListener, aContext,
1731+
aExternalNegotiated ? "true" : "false", aStream));
17031732
switch (type) {
17041733
case DATA_CHANNEL_RELIABLE:
17051734
prPolicy = SCTP_PR_SCTP_NONE;
@@ -1715,13 +1744,24 @@ DataChannelConnection::Open(const nsACString& label, Type type, bool inOrder,
17151744
return nullptr;
17161745
}
17171746

1747+
if (aStream != INVALID_STREAM && mStreams[aStream]) {
1748+
LOG(("ERROR: external negotiation of already-open channel %u", aStream));
1749+
// XXX How do we indicate this up to the application? Probably the
1750+
// caller's job, but we may need to return an error code.
1751+
return nullptr;
1752+
}
1753+
17181754
flags = !inOrder ? DATA_CHANNEL_FLAG_OUT_OF_ORDER_ALLOWED : 0;
17191755
nsRefPtr<DataChannel> channel(new DataChannel(this,
1720-
INVALID_STREAM,
1756+
aStream,
17211757
DataChannel::CONNECTING,
1722-
label, type, prValue,
1758+
label, protocol,
1759+
type, prValue,
17231760
flags,
17241761
aListener, aContext));
1762+
if (aExternalNegotiated) {
1763+
channel->mFlags |= DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED;
1764+
}
17251765

17261766
MutexAutoLock lock(mLock); // OpenFinish assumes this
17271767
return OpenFinish(channel.forget());
@@ -1731,38 +1771,42 @@ DataChannelConnection::Open(const nsACString& label, Type type, bool inOrder,
17311771
already_AddRefed<DataChannel>
17321772
DataChannelConnection::OpenFinish(already_AddRefed<DataChannel> aChannel)
17331773
{
1734-
uint16_t stream = FindFreeStream(); // may be INVALID_STREAM!
17351774
nsRefPtr<DataChannel> channel(aChannel);
1775+
uint16_t stream = channel->mStream;
17361776

1737-
mLock.AssertCurrentThreadOwns();
1777+
if (stream == INVALID_STREAM) {
1778+
stream = FindFreeStream(); // may be INVALID_STREAM!
17381779

1739-
LOG(("Finishing open: channel %p, stream = %u", channel.get(), stream));
1780+
mLock.AssertCurrentThreadOwns();
17401781

1741-
if (stream == INVALID_STREAM) {
1742-
if (!RequestMoreStreams()) {
1743-
channel->mState = CLOSED;
1744-
if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) {
1745-
// We already returned the channel to the app.
1746-
NS_ERROR("Failed to request more streams");
1747-
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
1748-
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
1749-
channel));
1750-
return channel.forget();
1782+
LOG(("Finishing open: channel %p, stream = %u", channel.get(), stream));
1783+
1784+
if (stream == INVALID_STREAM) {
1785+
if (!RequestMoreStreams()) {
1786+
channel->mState = CLOSED;
1787+
if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) {
1788+
// We already returned the channel to the app.
1789+
NS_ERROR("Failed to request more streams");
1790+
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
1791+
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
1792+
channel));
1793+
return channel.forget();
1794+
}
1795+
// we'll be destroying the channel, but it never really got set up
1796+
// Alternative would be to RUN_ON_THREAD(channel.forget(),::Destroy,...) and
1797+
// Dispatch it to ourselves
1798+
return nullptr;
17511799
}
1752-
// we'll be destroying the channel, but it never really got set up
1753-
// Alternative would be to RUN_ON_THREAD(channel.forget(),::Destroy,...) and
1754-
// Dispatch it to ourselves
1755-
return nullptr;
1800+
LOG(("Queuing channel %p to finish open", channel.get()));
1801+
// Also serves to mark we told the app
1802+
channel->mFlags |= DATA_CHANNEL_FLAGS_FINISH_OPEN;
1803+
channel->AddRef(); // we need a ref for the nsDeQue and one to return
1804+
mPending.Push(channel);
1805+
return channel.forget();
17561806
}
1757-
LOG(("Queuing channel %p to finish open", channel.get()));
1758-
// Also serves to mark we told the app
1759-
channel->mFlags |= DATA_CHANNEL_FLAGS_FINISH_OPEN;
1760-
channel->AddRef(); // we need a ref for the nsDeQue and one to return
1761-
mPending.Push(channel);
1762-
return channel.forget();
1807+
channel->mStream = stream;
17631808
}
17641809
mStreams[stream] = channel;
1765-
channel->mStream = stream;
17661810

17671811
#ifdef TEST_QUEUED_DATA
17681812
// It's painful to write a test for this...
@@ -1771,38 +1815,45 @@ DataChannelConnection::OpenFinish(already_AddRefed<DataChannel> aChannel)
17711815
SendMsgInternal(channel, "Help me!", 8, DATA_CHANNEL_PPID_DOMSTRING);
17721816
#endif
17731817

1774-
if (!SendOpenRequestMessage(channel->mLabel, stream,
1775-
!!(channel->mFlags & DATA_CHANNEL_FLAG_OUT_OF_ORDER_ALLOWED),
1776-
channel->mPrPolicy, channel->mPrValue)) {
1777-
LOG(("SendOpenRequest failed, errno = %d", errno));
1778-
if (errno == EAGAIN || errno == EWOULDBLOCK) {
1779-
channel->mFlags |= DATA_CHANNEL_FLAGS_SEND_REQ;
1780-
StartDefer();
1781-
} else {
1782-
if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) {
1783-
// We already returned the channel to the app.
1784-
NS_ERROR("Failed to send open request");
1785-
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
1786-
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
1787-
channel));
1818+
if (!(channel->mFlags & DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED)) {
1819+
if (!SendOpenRequestMessage(channel->mLabel, channel->mProtocol,
1820+
stream,
1821+
!!(channel->mFlags & DATA_CHANNEL_FLAG_OUT_OF_ORDER_ALLOWED),
1822+
channel->mPrPolicy, channel->mPrValue)) {
1823+
LOG(("SendOpenRequest failed, errno = %d", errno));
1824+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
1825+
channel->mFlags |= DATA_CHANNEL_FLAGS_SEND_REQ;
1826+
StartDefer();
1827+
1828+
return channel.forget();
1829+
} else {
1830+
if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) {
1831+
// We already returned the channel to the app.
1832+
NS_ERROR("Failed to send open request");
1833+
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
1834+
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
1835+
channel));
1836+
}
1837+
// If we haven't returned the channel yet, it will get destroyed when we exit
1838+
// this function.
1839+
mStreams[stream] = nullptr;
1840+
channel->mStream = INVALID_STREAM;
1841+
// we'll be destroying the channel
1842+
channel->mState = CLOSED;
1843+
return nullptr;
17881844
}
1789-
// If we haven't returned the channel yet, it will get destroyed when we exit
1790-
// this function.
1791-
mStreams[stream] = nullptr;
1792-
channel->mStream = INVALID_STREAM;
1793-
// we'll be destroying the channel
1794-
channel->mState = CLOSED;
1795-
return nullptr;
1845+
/* NOTREACHED */
17961846
}
1797-
} else {
1798-
channel->mState = OPEN;
1799-
channel->mReady = true;
1800-
// FIX? Move into DOMDataChannel? I don't think we can send it yet here
1801-
LOG(("%s: sending ON_CHANNEL_OPEN for %p", __FUNCTION__, channel.get()));
1802-
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
1803-
DataChannelOnMessageAvailable::ON_CHANNEL_OPEN, this,
1804-
channel));
18051847
}
1848+
// Either externally negotiated or we sent Open
1849+
channel->mState = OPEN;
1850+
channel->mReady = true;
1851+
// FIX? Move into DOMDataChannel? I don't think we can send it yet here
1852+
LOG(("%s: sending ON_CHANNEL_OPEN for %p", __FUNCTION__, channel.get()));
1853+
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
1854+
DataChannelOnMessageAvailable::ON_CHANNEL_OPEN, this,
1855+
channel));
1856+
18061857
return channel.forget();
18071858
}
18081859

netwerk/sctp/datachannel/DataChannel.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,13 @@ class DataChannelConnection: public nsITimerCallback
163163
} Type;
164164

165165
already_AddRefed<DataChannel> Open(const nsACString& label,
166+
const nsACString& protocol,
166167
Type type, bool inOrder,
167168
uint32_t prValue,
168169
DataChannelListener *aListener,
169-
nsISupports *aContext);
170+
nsISupports *aContext,
171+
bool aExternalNegotiated,
172+
uint16_t aStream);
170173

171174
void Close(DataChannel *aChannel);
172175
// CloseInt() must be called with mLock held
@@ -219,7 +222,8 @@ class DataChannelConnection: public nsITimerCallback
219222
uint16_t FindFreeStream();
220223
bool RequestMoreStreams(int32_t aNeeded = 16);
221224
int32_t SendControlMessage(void *msg, uint32_t len, uint16_t streamOut);
222-
int32_t SendOpenRequestMessage(const nsACString& label,uint16_t streamOut,
225+
int32_t SendOpenRequestMessage(const nsACString& label, const nsACString& protocol,
226+
uint16_t streamOut,
223227
bool unordered, uint16_t prPolicy, uint32_t prValue);
224228
int32_t SendMsgInternal(DataChannel *channel, const char *data,
225229
uint32_t length, uint32_t ppid);
@@ -314,6 +318,7 @@ class DataChannel {
314318
uint16_t stream,
315319
uint16_t state,
316320
const nsACString& label,
321+
const nsACString& protocol,
317322
uint16_t policy, uint32_t value,
318323
uint32_t flags,
319324
DataChannelListener *aListener,
@@ -323,6 +328,7 @@ class DataChannel {
323328
, mContext(aContext)
324329
, mConnection(connection)
325330
, mLabel(label)
331+
, mProtocol(protocol)
326332
, mState(state)
327333
, mReady(false)
328334
, mStream(stream)
@@ -396,6 +402,8 @@ class DataChannel {
396402
void SetReadyState(uint16_t aState) { mState = aState; }
397403

398404
void GetLabel(nsAString& aLabel) { CopyUTF8toUTF16(mLabel, aLabel); }
405+
void GetProtocol(nsAString& aProtocol) { CopyUTF8toUTF16(mProtocol, aProtocol); }
406+
void GetStream(uint16_t *aStream) { *aStream = mStream; }
399407

400408
void AppReady();
401409

@@ -414,6 +422,7 @@ class DataChannel {
414422

415423
nsRefPtr<DataChannelConnection> mConnection;
416424
nsCString mLabel;
425+
nsCString mProtocol;
417426
uint16_t mState;
418427
bool mReady;
419428
uint16_t mStream;

0 commit comments

Comments
 (0)