netwerk/sctp/datachannel/DataChannel.h

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     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/. */
     7 #ifndef NETWERK_SCTP_DATACHANNEL_DATACHANNEL_H_
     8 #define NETWERK_SCTP_DATACHANNEL_DATACHANNEL_H_
    10 #ifdef MOZ_WEBRTC_SIGNALING
    11 #define SCTP_DTLS_SUPPORTED 1
    12 #endif
    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 "nsITimer.h"
    25 #include "mozilla/Mutex.h"
    26 #include "DataChannelProtocol.h"
    27 #include "DataChannelListener.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
    36 #ifndef DATACHANNEL_LOG
    37 #define DATACHANNEL_LOG(args)
    38 #endif
    40 #ifndef EALREADY
    41 #define EALREADY  WSAEALREADY
    42 #endif
    44 extern "C" {
    45   struct socket;
    46   struct sctp_rcvinfo;
    47 }
    49 namespace mozilla {
    51 class DTLSConnection;
    52 class DataChannelConnection;
    53 class DataChannel;
    54 class DataChannelOnMessageAvailable;
    56 // For queuing outgoing messages
    57 class BufferedMsg
    58 {
    59 public:
    60   BufferedMsg(struct sctp_sendv_spa &spa,const char *data,
    61               uint32_t length);
    62   ~BufferedMsg();
    64   struct sctp_sendv_spa *mSpa;
    65   const char *mData;
    66   uint32_t mLength;
    67 };
    69 // for queuing incoming data messages before the Open or
    70 // external negotiation is indicated to us
    71 class QueuedDataMessage
    72 {
    73 public:
    74   QueuedDataMessage(uint16_t stream, uint32_t ppid,
    75              const void *data, size_t length)
    76     : mStream(stream)
    77     , mPpid(ppid)
    78     , mLength(length)
    79   {
    80     mData = static_cast<char *>(moz_xmalloc(length)); // infallible
    81     memcpy(mData, data, length);
    82   }
    84   ~QueuedDataMessage()
    85   {
    86     moz_free(mData);
    87   }
    89   uint16_t mStream;
    90   uint32_t mPpid;
    91   size_t   mLength;
    92   char     *mData;
    93 };
    95 // One per PeerConnection
    96 class DataChannelConnection: public nsITimerCallback
    97 #ifdef SCTP_DTLS_SUPPORTED
    98                              , public sigslot::has_slots<>
    99 #endif
   100 {
   101 public:
   102   NS_DECL_THREADSAFE_ISUPPORTS
   103   NS_DECL_NSITIMERCALLBACK
   105   class DataConnectionListener : public SupportsWeakPtr<DataConnectionListener>
   106   {
   107   public:
   108     MOZ_DECLARE_REFCOUNTED_TYPENAME(DataChannelConnection::DataConnectionListener)
   109     virtual ~DataConnectionListener() {}
   111     // Called when a the connection is open
   112     virtual void NotifyConnection() = 0;
   114     // Called when a the connection is lost/closed
   115     virtual void NotifyClosedConnection() = 0;
   117     // Called when a new DataChannel has been opened by the other side.
   118     virtual void NotifyDataChannel(already_AddRefed<DataChannel> channel) = 0;
   119   };
   121   DataChannelConnection(DataConnectionListener *listener);
   122   virtual ~DataChannelConnection();
   124   bool Init(unsigned short aPort, uint16_t aNumStreams, bool aUsingDtls);
   125   void Destroy(); // So we can spawn refs tied to runnables in shutdown
   126   // Finish Destroy on STS to avoid SCTP race condition with ABORT from far end
   127   void DestroyOnSTS(struct socket *aMasterSocket,
   128                     struct socket *aSocket);
   130 #ifdef ALLOW_DIRECT_SCTP_LISTEN_CONNECT
   131   // These block; they require something to decide on listener/connector
   132   // (though you can do simultaneous Connect()).  Do not call these from
   133   // the main thread!
   134   bool Listen(unsigned short port);
   135   bool Connect(const char *addr, unsigned short port);
   136 #endif
   138 #ifdef SCTP_DTLS_SUPPORTED
   139   // Connect using a TransportFlow (DTLS) channel
   140   void SetEvenOdd();
   141   bool ConnectViaTransportFlow(TransportFlow *aFlow, uint16_t localport, uint16_t remoteport);
   142   void CompleteConnect(TransportFlow *flow, TransportLayer::State state);
   143   void SetSignals();
   144 #endif
   146   typedef enum {
   147     RELIABLE=0,
   148     PARTIAL_RELIABLE_REXMIT = 1,
   149     PARTIAL_RELIABLE_TIMED = 2
   150   } Type;
   152   already_AddRefed<DataChannel> Open(const nsACString& label,
   153                                      const nsACString& protocol,
   154                                      Type type, bool inOrder,
   155                                      uint32_t prValue,
   156                                      DataChannelListener *aListener,
   157                                      nsISupports *aContext,
   158                                      bool aExternalNegotiated,
   159                                      uint16_t aStream) NS_WARN_UNUSED_RESULT;
   161   void Close(DataChannel *aChannel);
   162   // CloseInt() must be called with mLock held
   163   void CloseInt(DataChannel *aChannel);
   164   void CloseAll();
   166   int32_t SendMsg(uint16_t stream, const nsACString &aMsg)
   167     {
   168       return SendMsgCommon(stream, aMsg, false);
   169     }
   170   int32_t SendBinaryMsg(uint16_t stream, const nsACString &aMsg)
   171     {
   172       return SendMsgCommon(stream, aMsg, true);
   173     }
   174   int32_t SendBlob(uint16_t stream, nsIInputStream *aBlob);
   176   // Called on data reception from the SCTP library
   177   // must(?) be public so my c->c++ trampoline can call it
   178   int ReceiveCallback(struct socket* sock, void *data, size_t datalen,
   179                       struct sctp_rcvinfo rcv, int32_t flags);
   181   // Find out state
   182   enum {
   183     CONNECTING = 0U,
   184     OPEN = 1U,
   185     CLOSING = 2U,
   186     CLOSED = 3U
   187   };
   188   uint16_t GetReadyState() { MutexAutoLock lock(mLock); return mState; }
   190   friend class DataChannel;
   191   Mutex  mLock;
   193   void ReadBlob(already_AddRefed<DataChannelConnection> aThis, uint16_t aStream, nsIInputStream* aBlob);
   195   void GetStreamIds(std::vector<uint16_t>* aStreamList);
   197 protected:
   198   friend class DataChannelOnMessageAvailable;
   199   // Avoid cycles with PeerConnectionImpl
   200   // Use from main thread only as WeakPtr is not threadsafe
   201   WeakPtr<DataConnectionListener> mListener;
   203 private:
   204   friend class DataChannelConnectRunnable;
   206 #ifdef SCTP_DTLS_SUPPORTED
   207   static void DTLSConnectThread(void *data);
   208   int SendPacket(const unsigned char* data, size_t len, bool release);
   209   void SctpDtlsInput(TransportFlow *flow, const unsigned char *data, size_t len);
   210   static int SctpDtlsOutput(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df);
   211 #endif
   212   DataChannel* FindChannelByStream(uint16_t stream);
   213   uint16_t FindFreeStream();
   214   bool RequestMoreStreams(int32_t aNeeded = 16);
   215   int32_t SendControlMessage(void *msg, uint32_t len, uint16_t stream);
   216   int32_t SendOpenRequestMessage(const nsACString& label, const nsACString& protocol,
   217                                  uint16_t stream,
   218                                  bool unordered, uint16_t prPolicy, uint32_t prValue);
   219   int32_t SendOpenAckMessage(uint16_t stream);
   220   int32_t SendMsgInternal(DataChannel *channel, const char *data,
   221                           uint32_t length, uint32_t ppid);
   222   int32_t SendBinary(DataChannel *channel, const char *data,
   223                      uint32_t len, uint32_t ppid_partial, uint32_t ppid_final);
   224   int32_t SendMsgCommon(uint16_t stream, const nsACString &aMsg, bool isBinary);
   226   void DeliverQueuedData(uint16_t stream);
   228   already_AddRefed<DataChannel> OpenFinish(already_AddRefed<DataChannel>&& aChannel);
   230   void StartDefer();
   231   bool SendDeferredMessages();
   232   void ProcessQueuedOpens();
   233   void ClearResets();
   234   void SendOutgoingStreamReset();
   235   void ResetOutgoingStream(uint16_t stream);
   236   void HandleOpenRequestMessage(const struct rtcweb_datachannel_open_request *req,
   237                                 size_t length,
   238                                 uint16_t stream);
   239   void HandleOpenAckMessage(const struct rtcweb_datachannel_ack *ack,
   240                             size_t length, uint16_t stream);
   241   void HandleUnknownMessage(uint32_t ppid, size_t length, uint16_t stream);
   242   void HandleDataMessage(uint32_t ppid, const void *buffer, size_t length, uint16_t stream);
   243   void HandleMessage(const void *buffer, size_t length, uint32_t ppid, uint16_t stream);
   244   void HandleAssociationChangeEvent(const struct sctp_assoc_change *sac);
   245   void HandlePeerAddressChangeEvent(const struct sctp_paddr_change *spc);
   246   void HandleRemoteErrorEvent(const struct sctp_remote_error *sre);
   247   void HandleShutdownEvent(const struct sctp_shutdown_event *sse);
   248   void HandleAdaptationIndication(const struct sctp_adaptation_event *sai);
   249   void HandleSendFailedEvent(const struct sctp_send_failed_event *ssfe);
   250   void HandleStreamResetEvent(const struct sctp_stream_reset_event *strrst);
   251   void HandleStreamChangeEvent(const struct sctp_stream_change_event *strchg);
   252   void HandleNotification(const union sctp_notification *notif, size_t n);
   254 #ifdef SCTP_DTLS_SUPPORTED
   255   bool IsSTSThread() {
   256     bool on = false;
   257     if (mSTS) {
   258       mSTS->IsOnCurrentThread(&on);
   259     }
   260     return on;
   261   }
   262 #endif
   264   // Exists solely for proxying release of the TransportFlow to the STS thread
   265   static void ReleaseTransportFlow(nsRefPtr<TransportFlow> aFlow) {}
   267   // Data:
   268   // NOTE: while this array will auto-expand, increases in the number of
   269   // channels available from the stack must be negotiated!
   270   bool mAllocateEven;
   271   nsAutoTArray<nsRefPtr<DataChannel>,16> mStreams;
   272   nsDeque mPending; // Holds already_AddRefed<DataChannel>s -- careful!
   273   // holds data that's come in before a channel is open
   274   nsTArray<nsAutoPtr<QueuedDataMessage> > mQueuedData;
   276   // Streams pending reset
   277   nsAutoTArray<uint16_t,4> mStreamsResetting;
   279   struct socket *mMasterSocket; // accessed from STS thread
   280   struct socket *mSocket; // cloned from mMasterSocket on successful Connect on STS thread
   281   uint16_t mState; // Protected with mLock
   283 #ifdef SCTP_DTLS_SUPPORTED
   284   nsRefPtr<TransportFlow> mTransportFlow;
   285   nsCOMPtr<nsIEventTarget> mSTS;
   286 #endif
   287   uint16_t mLocalPort; // Accessed from connect thread
   288   uint16_t mRemotePort;
   289   bool mUsingDtls;
   291   // Timer to control when we try to resend blocked messages
   292   nsCOMPtr<nsITimer> mDeferredTimer;
   293   uint32_t mDeferTimeout; // in ms
   294   bool mTimerRunning;
   295   nsCOMPtr<nsIThread> mInternalIOThread;
   296 };
   298 #define ENSURE_DATACONNECTION \
   299   do { if (!mConnection) { DATACHANNEL_LOG(("%s: %p no connection!",__FUNCTION__, this)); return; } } while (0)
   301 #define ENSURE_DATACONNECTION_RET(x) \
   302   do { if (!mConnection) { DATACHANNEL_LOG(("%s: %p no connection!",__FUNCTION__, this)); return (x); } } while (0)
   304 class DataChannel {
   305 public:
   306   enum {
   307     CONNECTING = 0U,
   308     OPEN = 1U,
   309     CLOSING = 2U,
   310     CLOSED = 3U,
   311     WAITING_TO_OPEN = 4U
   312   };
   314   DataChannel(DataChannelConnection *connection,
   315               uint16_t stream,
   316               uint16_t state,
   317               const nsACString& label,
   318               const nsACString& protocol,
   319               uint16_t policy, uint32_t value,
   320               uint32_t flags,
   321               DataChannelListener *aListener,
   322               nsISupports *aContext)
   323     : mListenerLock("netwerk::sctp::DataChannel")
   324     , mListener(aListener)
   325     , mContext(aContext)
   326     , mConnection(connection)
   327     , mLabel(label)
   328     , mProtocol(protocol)
   329     , mState(state)
   330     , mReady(false)
   331     , mStream(stream)
   332     , mPrPolicy(policy)
   333     , mPrValue(value)
   334     , mFlags(flags)
   335     , mIsRecvBinary(false)
   336     {
   337       NS_ASSERTION(mConnection,"NULL connection");
   338     }
   340   ~DataChannel();
   341   void Destroy(); // when we disconnect from the connection after stream RESET
   343   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataChannel)
   345   // Close this DataChannel.  Can be called multiple times.  MUST be called
   346   // before destroying the DataChannel (state must be CLOSED or CLOSING).
   347   void Close();
   349   // Set the listener (especially for channels created from the other side)
   350   void SetListener(DataChannelListener *aListener, nsISupports *aContext);
   352   // Send a string
   353   bool SendMsg(const nsACString &aMsg)
   354     {
   355       ENSURE_DATACONNECTION_RET(false);
   357       if (mStream != INVALID_STREAM)
   358         return (mConnection->SendMsg(mStream, aMsg) > 0);
   359       else
   360         return false;
   361     }
   363   // Send a binary message (TypedArray)
   364   bool SendBinaryMsg(const nsACString &aMsg)
   365     {
   366       ENSURE_DATACONNECTION_RET(false);
   368       if (mStream != INVALID_STREAM)
   369         return (mConnection->SendBinaryMsg(mStream, aMsg) > 0);
   370       else
   371         return false;
   372     }
   374   // Send a binary blob
   375   bool SendBinaryStream(nsIInputStream *aBlob, uint32_t msgLen)
   376     {
   377       ENSURE_DATACONNECTION_RET(false);
   379       if (mStream != INVALID_STREAM)
   380         return (mConnection->SendBlob(mStream, aBlob) > 0);
   381       else
   382         return false;
   383     }
   385   uint16_t GetType() { return mPrPolicy; }
   387   bool GetOrdered() { return !(mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED); }
   389   // Amount of data buffered to send
   390   uint32_t GetBufferedAmount();
   392   // Find out state
   393   uint16_t GetReadyState()
   394     {
   395       if (mConnection) {
   396         MutexAutoLock lock(mConnection->mLock);
   397         if (mState == WAITING_TO_OPEN)
   398           return CONNECTING;
   399         return mState;
   400       }
   401       return CLOSED;
   402     }
   404   void GetLabel(nsAString& aLabel) { CopyUTF8toUTF16(mLabel, aLabel); }
   405   void GetProtocol(nsAString& aProtocol) { CopyUTF8toUTF16(mProtocol, aProtocol); }
   406   uint16_t GetStream() { return mStream; }
   408   void AppReady();
   410   void SendOrQueue(DataChannelOnMessageAvailable *aMessage);
   412 protected:
   413   Mutex mListenerLock; // protects mListener and mContext
   414   DataChannelListener *mListener;
   415   nsCOMPtr<nsISupports> mContext;
   417 private:
   418   friend class DataChannelOnMessageAvailable;
   419   friend class DataChannelConnection;
   421   nsresult AddDataToBinaryMsg(const char *data, uint32_t size);
   423   nsRefPtr<DataChannelConnection> mConnection;
   424   nsCString mLabel;
   425   nsCString mProtocol;
   426   uint16_t mState;
   427   bool     mReady;
   428   uint16_t mStream;
   429   uint16_t mPrPolicy;
   430   uint32_t mPrValue;
   431   uint32_t mFlags;
   432   uint32_t mId;
   433   bool mIsRecvBinary;
   434   nsCString mRecvBuffer;
   435   nsTArray<nsAutoPtr<BufferedMsg> > mBufferedData;
   436   nsTArray<nsCOMPtr<nsIRunnable> > mQueuedMessages;
   437 };
   439 // used to dispatch notifications of incoming data to the main thread
   440 // Patterned on CallOnMessageAvailable in WebSockets
   441 // Also used to proxy other items to MainThread
   442 class DataChannelOnMessageAvailable : public nsRunnable
   443 {
   444 public:
   445   enum {
   446     ON_CONNECTION,
   447     ON_DISCONNECTED,
   448     ON_CHANNEL_CREATED,
   449     ON_CHANNEL_OPEN,
   450     ON_CHANNEL_CLOSED,
   451     ON_DATA,
   452     START_DEFER,
   453   };  /* types */
   455   DataChannelOnMessageAvailable(int32_t     aType,
   456                                 DataChannelConnection *aConnection,
   457                                 DataChannel *aChannel,
   458                                 nsCString   &aData,  // XXX this causes inefficiency
   459                                 int32_t     aLen)
   460     : mType(aType),
   461       mChannel(aChannel),
   462       mConnection(aConnection),
   463       mData(aData),
   464       mLen(aLen) {}
   466   DataChannelOnMessageAvailable(int32_t     aType,
   467                                 DataChannel *aChannel)
   468     : mType(aType),
   469       mChannel(aChannel) {}
   470   // XXX is it safe to leave mData/mLen uninitialized?  This should only be
   471   // used for notifications that don't use them, but I'd like more
   472   // bulletproof compile-time checking.
   474   DataChannelOnMessageAvailable(int32_t     aType,
   475                                 DataChannelConnection *aConnection,
   476                                 DataChannel *aChannel)
   477     : mType(aType),
   478       mChannel(aChannel),
   479       mConnection(aConnection) {}
   481   // for ON_CONNECTION/ON_DISCONNECTED
   482   DataChannelOnMessageAvailable(int32_t     aType,
   483                                 DataChannelConnection *aConnection,
   484                                 bool aResult = true)
   485     : mType(aType),
   486       mConnection(aConnection),
   487       mResult(aResult) {}
   489   NS_IMETHOD Run()
   490   {
   491     MOZ_ASSERT(NS_IsMainThread());
   492     switch (mType) {
   493       case ON_DATA:
   494       case ON_CHANNEL_OPEN:
   495       case ON_CHANNEL_CLOSED:
   496         {
   497           MutexAutoLock lock(mChannel->mListenerLock);
   498           if (!mChannel->mListener) {
   499             DATACHANNEL_LOG(("DataChannelOnMessageAvailable (%d) with null Listener!",mType));
   500             return NS_OK;
   501           }
   503           switch (mType) {
   504             case ON_DATA:
   505               if (mLen < 0) {
   506                 mChannel->mListener->OnMessageAvailable(mChannel->mContext, mData);
   507               } else {
   508                 mChannel->mListener->OnBinaryMessageAvailable(mChannel->mContext, mData);
   509               }
   510               break;
   511             case ON_CHANNEL_OPEN:
   512               mChannel->mListener->OnChannelConnected(mChannel->mContext);
   513               break;
   514             case ON_CHANNEL_CLOSED:
   515               mChannel->mListener->OnChannelClosed(mChannel->mContext);
   516               break;
   517           }
   518           break;
   519         }
   520       case ON_DISCONNECTED:
   521         // If we've disconnected, make sure we close all the streams - from mainthread!
   522         mConnection->CloseAll();
   523         // fall through
   524       case ON_CHANNEL_CREATED:
   525       case ON_CONNECTION:
   526         // WeakPtr - only used/modified/nulled from MainThread so we can use a WeakPtr here
   527         if (!mConnection->mListener) {
   528           DATACHANNEL_LOG(("DataChannelOnMessageAvailable (%d) with null Listener",mType));
   529           return NS_OK;
   530         }
   531         switch (mType) {
   532           case ON_CHANNEL_CREATED:
   533             // important to give it an already_AddRefed pointer!
   534             mConnection->mListener->NotifyDataChannel(mChannel.forget());
   535             break;
   536           case ON_CONNECTION:
   537             if (mResult) {
   538               mConnection->mListener->NotifyConnection();
   539             }
   540             // FIX - on mResult false (failure) we should do something.  Needs spec work here
   541             break;
   542           case ON_DISCONNECTED:
   543             mConnection->mListener->NotifyClosedConnection();
   544             break;
   545         }
   546         break;
   547       case START_DEFER:
   548         mConnection->StartDefer();
   549         break;
   550     }
   551     return NS_OK;
   552   }
   554 private:
   555   ~DataChannelOnMessageAvailable() {}
   557   int32_t                           mType;
   558   // XXX should use union
   559   nsRefPtr<DataChannel>             mChannel;
   560   nsRefPtr<DataChannelConnection>   mConnection;
   561   nsCString                         mData;
   562   int32_t                           mLen;
   563   bool                              mResult;
   564 };
   566 }
   568 #endif  // NETWERK_SCTP_DATACHANNEL_DATACHANNEL_H_

mercurial