Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef NETWERK_SCTP_DATACHANNEL_DATACHANNEL_H_
8 : #define NETWERK_SCTP_DATACHANNEL_DATACHANNEL_H_
9 :
10 : #ifdef MOZ_WEBRTC_SIGNALING
11 : #define SCTP_DTLS_SUPPORTED 1
12 : #endif
13 :
14 : #include <string>
15 : #include <errno.h>
16 : #include "nsISupports.h"
17 : #include "nsCOMPtr.h"
18 : #include "mozilla/WeakPtr.h"
19 : #include "nsString.h"
20 : #include "nsThreadUtils.h"
21 : #include "nsTArray.h"
22 : #include "nsDeque.h"
23 : #include "nsIInputStream.h"
24 : #include "mozilla/Mutex.h"
25 : #include "DataChannelProtocol.h"
26 : #include "DataChannelListener.h"
27 : #include "mozilla/net/NeckoTargetHolder.h"
28 : #ifdef SCTP_DTLS_SUPPORTED
29 : #include "mtransport/sigslot.h"
30 : #include "mtransport/transportflow.h"
31 : #include "mtransport/transportlayer.h"
32 : #include "mtransport/transportlayerdtls.h"
33 : #include "mtransport/transportlayerprsock.h"
34 : #endif
35 :
36 : #ifndef DATACHANNEL_LOG
37 : #define DATACHANNEL_LOG(args)
38 : #endif
39 :
40 : #ifndef EALREADY
41 : #define EALREADY WSAEALREADY
42 : #endif
43 :
44 : extern "C" {
45 : struct socket;
46 : struct sctp_rcvinfo;
47 : }
48 :
49 : namespace mozilla {
50 :
51 : class DataChannelConnection;
52 : class DataChannel;
53 : class DataChannelOnMessageAvailable;
54 :
55 : // For queuing outgoing messages
56 : class BufferedMsg
57 : {
58 : public:
59 : BufferedMsg(struct sctp_sendv_spa &spa,const char *data,
60 : size_t length);
61 : ~BufferedMsg();
62 :
63 : struct sctp_sendv_spa *mSpa;
64 : const char *mData;
65 : size_t mLength;
66 : };
67 :
68 : // for queuing incoming data messages before the Open or
69 : // external negotiation is indicated to us
70 : class QueuedDataMessage
71 : {
72 : public:
73 0 : QueuedDataMessage(uint16_t stream, uint32_t ppid,
74 : const void *data, size_t length)
75 0 : : mStream(stream)
76 : , mPpid(ppid)
77 0 : , mLength(length)
78 : {
79 0 : mData = static_cast<char *>(moz_xmalloc(length)); // infallible
80 0 : memcpy(mData, data, length);
81 0 : }
82 :
83 0 : ~QueuedDataMessage()
84 0 : {
85 0 : free(mData);
86 0 : }
87 :
88 : uint16_t mStream;
89 : uint32_t mPpid;
90 : size_t mLength;
91 : char *mData;
92 : };
93 :
94 : // One per PeerConnection
95 : class DataChannelConnection final
96 : : public net::NeckoTargetHolder
97 : #ifdef SCTP_DTLS_SUPPORTED
98 : , public sigslot::has_slots<>
99 : #endif
100 : {
101 : virtual ~DataChannelConnection();
102 :
103 : public:
104 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataChannelConnection)
105 :
106 0 : class DataConnectionListener : public SupportsWeakPtr<DataConnectionListener>
107 : {
108 : public:
109 0 : MOZ_DECLARE_WEAKREFERENCE_TYPENAME(DataChannelConnection::DataConnectionListener)
110 0 : virtual ~DataConnectionListener() {}
111 :
112 : // Called when a new DataChannel has been opened by the other side.
113 : virtual void NotifyDataChannel(already_AddRefed<DataChannel> channel) = 0;
114 : };
115 :
116 : explicit DataChannelConnection(DataConnectionListener *listener,
117 : nsIEventTarget *aTarget);
118 :
119 : bool Init(unsigned short aPort, uint16_t aNumStreams, bool aUsingDtls);
120 : void Destroy(); // So we can spawn refs tied to runnables in shutdown
121 : // Finish Destroy on STS to avoid SCTP race condition with ABORT from far end
122 : void DestroyOnSTS(struct socket *aMasterSocket,
123 : struct socket *aSocket);
124 :
125 : #ifdef ALLOW_DIRECT_SCTP_LISTEN_CONNECT
126 : // These block; they require something to decide on listener/connector
127 : // (though you can do simultaneous Connect()). Do not call these from
128 : // the main thread!
129 : bool Listen(unsigned short port);
130 : bool Connect(const char *addr, unsigned short port);
131 : #endif
132 :
133 : #ifdef SCTP_DTLS_SUPPORTED
134 : // Connect using a TransportFlow (DTLS) channel
135 : void SetEvenOdd();
136 : bool ConnectViaTransportFlow(TransportFlow *aFlow, uint16_t localport, uint16_t remoteport);
137 : void CompleteConnect(TransportFlow *flow, TransportLayer::State state);
138 : void SetSignals();
139 : #endif
140 :
141 : typedef enum {
142 : RELIABLE=0,
143 : PARTIAL_RELIABLE_REXMIT = 1,
144 : PARTIAL_RELIABLE_TIMED = 2
145 : } Type;
146 :
147 : MOZ_MUST_USE
148 : already_AddRefed<DataChannel> Open(const nsACString& label,
149 : const nsACString& protocol,
150 : Type type, bool inOrder,
151 : uint32_t prValue,
152 : DataChannelListener *aListener,
153 : nsISupports *aContext,
154 : bool aExternalNegotiated,
155 : uint16_t aStream);
156 :
157 : void Close(DataChannel *aChannel);
158 : // CloseInt() must be called with mLock held
159 : void CloseInt(DataChannel *aChannel);
160 : void CloseAll();
161 :
162 0 : int32_t SendMsg(uint16_t stream, const nsACString &aMsg)
163 : {
164 0 : return SendMsgCommon(stream, aMsg, false);
165 : }
166 0 : int32_t SendBinaryMsg(uint16_t stream, const nsACString &aMsg)
167 : {
168 0 : return SendMsgCommon(stream, aMsg, true);
169 : }
170 : int32_t SendBlob(uint16_t stream, nsIInputStream *aBlob);
171 :
172 : // Called on data reception from the SCTP library
173 : // must(?) be public so my c->c++ trampoline can call it
174 : int ReceiveCallback(struct socket* sock, void *data, size_t datalen,
175 : struct sctp_rcvinfo rcv, int32_t flags);
176 :
177 : // Find out state
178 : enum {
179 : CONNECTING = 0U,
180 : OPEN = 1U,
181 : CLOSING = 2U,
182 : CLOSED = 3U
183 : };
184 : uint16_t GetReadyState() { MutexAutoLock lock(mLock); return mState; }
185 :
186 : friend class DataChannel;
187 : Mutex mLock;
188 :
189 : void ReadBlob(already_AddRefed<DataChannelConnection> aThis, uint16_t aStream, nsIInputStream* aBlob);
190 :
191 : void GetStreamIds(std::vector<uint16_t>* aStreamList);
192 :
193 : bool SendDeferredMessages();
194 :
195 : protected:
196 : friend class DataChannelOnMessageAvailable;
197 : // Avoid cycles with PeerConnectionImpl
198 : // Use from main thread only as WeakPtr is not threadsafe
199 : WeakPtr<DataConnectionListener> mListener;
200 :
201 : private:
202 : friend class DataChannelConnectRunnable;
203 :
204 : #ifdef SCTP_DTLS_SUPPORTED
205 : static void DTLSConnectThread(void *data);
206 : int SendPacket(unsigned char data[], size_t len, bool release);
207 : void SctpDtlsInput(TransportFlow *flow, const unsigned char *data, size_t len);
208 : static int SctpDtlsOutput(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df);
209 : #endif
210 : DataChannel* FindChannelByStream(uint16_t stream);
211 : uint16_t FindFreeStream();
212 : bool RequestMoreStreams(int32_t aNeeded = 16);
213 : int32_t SendControlMessage(void *msg, uint32_t len, uint16_t stream);
214 : int32_t SendOpenRequestMessage(const nsACString& label, const nsACString& protocol,
215 : uint16_t stream,
216 : bool unordered, uint16_t prPolicy, uint32_t prValue);
217 : int32_t SendOpenAckMessage(uint16_t stream);
218 : int32_t SendMsgInternal(DataChannel *channel, const char *data,
219 : size_t length, uint32_t ppid);
220 : int32_t SendBinary(DataChannel *channel, const char *data,
221 : size_t len, uint32_t ppid_partial, uint32_t ppid_final);
222 : int32_t SendMsgCommon(uint16_t stream, const nsACString &aMsg, bool isBinary);
223 :
224 : void DeliverQueuedData(uint16_t stream);
225 :
226 : already_AddRefed<DataChannel> OpenFinish(already_AddRefed<DataChannel>&& aChannel);
227 :
228 : void ProcessQueuedOpens();
229 : void ClearResets();
230 : void SendOutgoingStreamReset();
231 : void ResetOutgoingStream(uint16_t stream);
232 : void HandleOpenRequestMessage(const struct rtcweb_datachannel_open_request *req,
233 : size_t length,
234 : uint16_t stream);
235 : void HandleOpenAckMessage(const struct rtcweb_datachannel_ack *ack,
236 : size_t length, uint16_t stream);
237 : void HandleUnknownMessage(uint32_t ppid, size_t length, uint16_t stream);
238 : void HandleDataMessage(uint32_t ppid, const void *buffer, size_t length, uint16_t stream);
239 : void HandleMessage(const void *buffer, size_t length, uint32_t ppid, uint16_t stream);
240 : void HandleAssociationChangeEvent(const struct sctp_assoc_change *sac);
241 : void HandlePeerAddressChangeEvent(const struct sctp_paddr_change *spc);
242 : void HandleRemoteErrorEvent(const struct sctp_remote_error *sre);
243 : void HandleShutdownEvent(const struct sctp_shutdown_event *sse);
244 : void HandleAdaptationIndication(const struct sctp_adaptation_event *sai);
245 : void HandleSendFailedEvent(const struct sctp_send_failed_event *ssfe);
246 : void HandleStreamResetEvent(const struct sctp_stream_reset_event *strrst);
247 : void HandleStreamChangeEvent(const struct sctp_stream_change_event *strchg);
248 : void HandleNotification(const union sctp_notification *notif, size_t n);
249 :
250 : #ifdef SCTP_DTLS_SUPPORTED
251 0 : bool IsSTSThread() {
252 0 : bool on = false;
253 0 : if (mSTS) {
254 0 : mSTS->IsOnCurrentThread(&on);
255 : }
256 0 : return on;
257 : }
258 : #endif
259 :
260 : // Exists solely for proxying release of the TransportFlow to the STS thread
261 : static void ReleaseTransportFlow(const RefPtr<TransportFlow>& aFlow) {}
262 :
263 : // Data:
264 : // NOTE: while this array will auto-expand, increases in the number of
265 : // channels available from the stack must be negotiated!
266 : bool mAllocateEven;
267 : AutoTArray<RefPtr<DataChannel>,16> mStreams;
268 : nsDeque mPending; // Holds addref'ed DataChannel's -- careful!
269 : // holds data that's come in before a channel is open
270 : nsTArray<nsAutoPtr<QueuedDataMessage>> mQueuedData;
271 :
272 : // Streams pending reset
273 : AutoTArray<uint16_t,4> mStreamsResetting;
274 :
275 : struct socket *mMasterSocket; // accessed from STS thread
276 : struct socket *mSocket; // cloned from mMasterSocket on successful Connect on STS thread
277 : uint16_t mState; // Protected with mLock
278 :
279 : #ifdef SCTP_DTLS_SUPPORTED
280 : RefPtr<TransportFlow> mTransportFlow;
281 : nsCOMPtr<nsIEventTarget> mSTS;
282 : #endif
283 : uint16_t mLocalPort; // Accessed from connect thread
284 : uint16_t mRemotePort;
285 : bool mUsingDtls;
286 :
287 : nsCOMPtr<nsIThread> mInternalIOThread;
288 : };
289 :
290 : #define ENSURE_DATACONNECTION \
291 : do { MOZ_ASSERT(mConnection); if (!mConnection) { return; } } while (0)
292 :
293 : #define ENSURE_DATACONNECTION_RET(x) \
294 : do { MOZ_ASSERT(mConnection); if (!mConnection) { return (x); } } while (0)
295 :
296 : class DataChannel {
297 : public:
298 : enum {
299 : CONNECTING = 0U,
300 : OPEN = 1U,
301 : CLOSING = 2U,
302 : CLOSED = 3U,
303 : WAITING_TO_OPEN = 4U
304 : };
305 :
306 0 : DataChannel(DataChannelConnection *connection,
307 : uint16_t stream,
308 : uint16_t state,
309 : const nsACString& label,
310 : const nsACString& protocol,
311 : uint16_t policy, uint32_t value,
312 : uint32_t flags,
313 : DataChannelListener *aListener,
314 : nsISupports *aContext)
315 0 : : mListenerLock("netwerk::sctp::DataChannel")
316 : , mListener(aListener)
317 : , mContext(aContext)
318 : , mConnection(connection)
319 : , mLabel(label)
320 : , mProtocol(protocol)
321 : , mState(state)
322 : , mReady(false)
323 : , mStream(stream)
324 : , mPrPolicy(policy)
325 : , mPrValue(value)
326 : , mFlags(flags)
327 : , mIsRecvBinary(false)
328 : , mBufferedThreshold(0) // default from spec
329 0 : , mMainThreadEventTarget(connection->GetNeckoTarget())
330 : {
331 0 : NS_ASSERTION(mConnection,"NULL connection");
332 0 : }
333 :
334 : private:
335 : ~DataChannel();
336 :
337 : public:
338 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataChannel)
339 :
340 : // when we disconnect from the connection after stream RESET
341 : void StreamClosedLocked();
342 :
343 : // Complete dropping of the link between DataChannel and the connection.
344 : // After this, except for a few methods below listed to be safe, you can't
345 : // call into DataChannel.
346 : void ReleaseConnection();
347 :
348 : // Close this DataChannel. Can be called multiple times. MUST be called
349 : // before destroying the DataChannel (state must be CLOSED or CLOSING).
350 : void Close();
351 :
352 : // Set the listener (especially for channels created from the other side)
353 : void SetListener(DataChannelListener *aListener, nsISupports *aContext);
354 :
355 : // Send a string
356 0 : bool SendMsg(const nsACString &aMsg)
357 : {
358 0 : ENSURE_DATACONNECTION_RET(false);
359 :
360 0 : if (mStream != INVALID_STREAM)
361 0 : return (mConnection->SendMsg(mStream, aMsg) >= 0);
362 : else
363 0 : return false;
364 : }
365 :
366 : // Send a binary message (TypedArray)
367 0 : bool SendBinaryMsg(const nsACString &aMsg)
368 : {
369 0 : ENSURE_DATACONNECTION_RET(false);
370 :
371 0 : if (mStream != INVALID_STREAM)
372 0 : return (mConnection->SendBinaryMsg(mStream, aMsg) >= 0);
373 : else
374 0 : return false;
375 : }
376 :
377 : // Send a binary blob
378 0 : bool SendBinaryStream(nsIInputStream *aBlob, uint32_t msgLen)
379 : {
380 0 : ENSURE_DATACONNECTION_RET(false);
381 :
382 0 : if (mStream != INVALID_STREAM)
383 0 : return (mConnection->SendBlob(mStream, aBlob) == 0);
384 : else
385 0 : return false;
386 : }
387 :
388 0 : uint16_t GetType() { return mPrPolicy; }
389 :
390 0 : bool GetOrdered() { return !(mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED); }
391 :
392 : // Amount of data buffered to send
393 0 : uint32_t GetBufferedAmount()
394 : {
395 0 : if (!mConnection) {
396 0 : return 0;
397 : }
398 :
399 0 : MutexAutoLock lock(mConnection->mLock);
400 0 : return GetBufferedAmountLocked();
401 : }
402 :
403 :
404 : // Trigger amount for generating BufferedAmountLow events
405 : uint32_t GetBufferedAmountLowThreshold();
406 : void SetBufferedAmountLowThreshold(uint32_t aThreshold);
407 :
408 : // Find out state
409 0 : uint16_t GetReadyState()
410 : {
411 0 : if (mConnection) {
412 0 : MutexAutoLock lock(mConnection->mLock);
413 0 : if (mState == WAITING_TO_OPEN)
414 0 : return CONNECTING;
415 0 : return mState;
416 : }
417 0 : return CLOSED;
418 : }
419 :
420 0 : void GetLabel(nsAString& aLabel) { CopyUTF8toUTF16(mLabel, aLabel); }
421 0 : void GetProtocol(nsAString& aProtocol) { CopyUTF8toUTF16(mProtocol, aProtocol); }
422 0 : uint16_t GetStream() { return mStream; }
423 :
424 : void AppReady();
425 :
426 : void SendOrQueue(DataChannelOnMessageAvailable *aMessage);
427 :
428 : protected:
429 : Mutex mListenerLock; // protects mListener and mContext
430 : DataChannelListener *mListener;
431 : nsCOMPtr<nsISupports> mContext;
432 :
433 : private:
434 : friend class DataChannelOnMessageAvailable;
435 : friend class DataChannelConnection;
436 :
437 : nsresult AddDataToBinaryMsg(const char *data, uint32_t size);
438 : uint32_t GetBufferedAmountLocked() const;
439 :
440 : RefPtr<DataChannelConnection> mConnection;
441 : nsCString mLabel;
442 : nsCString mProtocol;
443 : uint16_t mState;
444 : bool mReady;
445 : uint16_t mStream;
446 : uint16_t mPrPolicy;
447 : uint32_t mPrValue;
448 : uint32_t mFlags;
449 : uint32_t mId;
450 : bool mIsRecvBinary;
451 : size_t mBufferedThreshold;
452 : nsCString mRecvBuffer;
453 : nsTArray<nsAutoPtr<BufferedMsg>> mBufferedData; // GUARDED_BY(mConnection->mLock)
454 : nsTArray<nsCOMPtr<nsIRunnable>> mQueuedMessages;
455 : nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
456 : };
457 :
458 : // used to dispatch notifications of incoming data to the main thread
459 : // Patterned on CallOnMessageAvailable in WebSockets
460 : // Also used to proxy other items to MainThread
461 : class DataChannelOnMessageAvailable : public Runnable
462 : {
463 : public:
464 : enum {
465 : ON_CONNECTION,
466 : ON_DISCONNECTED,
467 : ON_CHANNEL_CREATED,
468 : ON_CHANNEL_OPEN,
469 : ON_CHANNEL_CLOSED,
470 : ON_DATA,
471 : BUFFER_LOW_THRESHOLD,
472 : NO_LONGER_BUFFERED,
473 : }; /* types */
474 :
475 0 : DataChannelOnMessageAvailable(
476 : int32_t aType,
477 : DataChannelConnection* aConnection,
478 : DataChannel* aChannel,
479 : nsCString& aData, // XXX this causes inefficiency
480 : int32_t aLen)
481 0 : : Runnable("DataChannelOnMessageAvailable")
482 : , mType(aType)
483 : , mChannel(aChannel)
484 : , mConnection(aConnection)
485 : , mData(aData)
486 0 : , mLen(aLen)
487 : {
488 0 : }
489 :
490 : DataChannelOnMessageAvailable(int32_t aType, DataChannel* aChannel)
491 : : Runnable("DataChannelOnMessageAvailable")
492 : , mType(aType)
493 : , mChannel(aChannel)
494 : {
495 : }
496 : // XXX is it safe to leave mData/mLen uninitialized? This should only be
497 : // used for notifications that don't use them, but I'd like more
498 : // bulletproof compile-time checking.
499 :
500 0 : DataChannelOnMessageAvailable(int32_t aType,
501 : DataChannelConnection* aConnection,
502 : DataChannel* aChannel)
503 0 : : Runnable("DataChannelOnMessageAvailable")
504 : , mType(aType)
505 : , mChannel(aChannel)
506 0 : , mConnection(aConnection)
507 : {
508 0 : }
509 :
510 : // for ON_CONNECTION/ON_DISCONNECTED
511 0 : DataChannelOnMessageAvailable(int32_t aType,
512 : DataChannelConnection* aConnection)
513 0 : : Runnable("DataChannelOnMessageAvailable")
514 : , mType(aType)
515 0 : , mConnection(aConnection)
516 : {
517 0 : }
518 :
519 0 : NS_IMETHOD Run() override
520 : {
521 0 : MOZ_ASSERT(NS_IsMainThread());
522 :
523 : // Note: calling the listeners can indirectly cause the listeners to be
524 : // made available for GC (by removing event listeners), especially for
525 : // OnChannelClosed(). We hold a ref to the Channel and the listener
526 : // while calling this.
527 0 : switch (mType) {
528 : case ON_DATA:
529 : case ON_CHANNEL_OPEN:
530 : case ON_CHANNEL_CLOSED:
531 : case BUFFER_LOW_THRESHOLD:
532 : case NO_LONGER_BUFFERED:
533 : {
534 0 : MutexAutoLock lock(mChannel->mListenerLock);
535 0 : if (!mChannel->mListener) {
536 0 : DATACHANNEL_LOG(("DataChannelOnMessageAvailable (%d) with null Listener!",mType));
537 0 : return NS_OK;
538 : }
539 :
540 0 : switch (mType) {
541 : case ON_DATA:
542 0 : if (mLen < 0) {
543 0 : mChannel->mListener->OnMessageAvailable(mChannel->mContext, mData);
544 : } else {
545 0 : mChannel->mListener->OnBinaryMessageAvailable(mChannel->mContext, mData);
546 : }
547 0 : break;
548 : case ON_CHANNEL_OPEN:
549 0 : mChannel->mListener->OnChannelConnected(mChannel->mContext);
550 0 : break;
551 : case ON_CHANNEL_CLOSED:
552 0 : mChannel->mListener->OnChannelClosed(mChannel->mContext);
553 0 : break;
554 : case BUFFER_LOW_THRESHOLD:
555 0 : mChannel->mListener->OnBufferLow(mChannel->mContext);
556 0 : break;
557 : case NO_LONGER_BUFFERED:
558 0 : mChannel->mListener->NotBuffered(mChannel->mContext);
559 0 : break;
560 : }
561 0 : break;
562 : }
563 : case ON_DISCONNECTED:
564 : // If we've disconnected, make sure we close all the streams - from mainthread!
565 0 : mConnection->CloseAll();
566 : MOZ_FALLTHROUGH;
567 : case ON_CHANNEL_CREATED:
568 : case ON_CONNECTION:
569 : // WeakPtr - only used/modified/nulled from MainThread so we can use a WeakPtr here
570 0 : if (!mConnection->mListener) {
571 0 : DATACHANNEL_LOG(("DataChannelOnMessageAvailable (%d) with null Listener",mType));
572 0 : return NS_OK;
573 : }
574 0 : switch (mType) {
575 : case ON_CHANNEL_CREATED:
576 : // important to give it an already_AddRefed pointer!
577 0 : mConnection->mListener->NotifyDataChannel(mChannel.forget());
578 0 : break;
579 : default:
580 0 : break;
581 : }
582 0 : break;
583 : }
584 0 : return NS_OK;
585 : }
586 :
587 : private:
588 0 : ~DataChannelOnMessageAvailable() {}
589 :
590 : int32_t mType;
591 : // XXX should use union
592 : RefPtr<DataChannel> mChannel;
593 : RefPtr<DataChannelConnection> mConnection;
594 : nsCString mData;
595 : int32_t mLen;
596 : };
597 :
598 : }
599 :
600 : #endif // NETWERK_SCTP_DATACHANNEL_DATACHANNEL_H_
|