netwerk/sctp/datachannel/DataChannel.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/sctp/datachannel/DataChannel.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,568 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef NETWERK_SCTP_DATACHANNEL_DATACHANNEL_H_
    1.11 +#define NETWERK_SCTP_DATACHANNEL_DATACHANNEL_H_
    1.12 +
    1.13 +#ifdef MOZ_WEBRTC_SIGNALING
    1.14 +#define SCTP_DTLS_SUPPORTED 1
    1.15 +#endif
    1.16 +
    1.17 +#include <string>
    1.18 +#include <errno.h>
    1.19 +#include "nsISupports.h"
    1.20 +#include "nsCOMPtr.h"
    1.21 +#include "mozilla/WeakPtr.h"
    1.22 +#include "nsString.h"
    1.23 +#include "nsThreadUtils.h"
    1.24 +#include "nsTArray.h"
    1.25 +#include "nsDeque.h"
    1.26 +#include "nsIInputStream.h"
    1.27 +#include "nsITimer.h"
    1.28 +#include "mozilla/Mutex.h"
    1.29 +#include "DataChannelProtocol.h"
    1.30 +#include "DataChannelListener.h"
    1.31 +#ifdef SCTP_DTLS_SUPPORTED
    1.32 +#include "mtransport/sigslot.h"
    1.33 +#include "mtransport/transportflow.h"
    1.34 +#include "mtransport/transportlayer.h"
    1.35 +#include "mtransport/transportlayerdtls.h"
    1.36 +#include "mtransport/transportlayerprsock.h"
    1.37 +#endif
    1.38 +
    1.39 +#ifndef DATACHANNEL_LOG
    1.40 +#define DATACHANNEL_LOG(args)
    1.41 +#endif
    1.42 +
    1.43 +#ifndef EALREADY
    1.44 +#define EALREADY  WSAEALREADY
    1.45 +#endif
    1.46 +
    1.47 +extern "C" {
    1.48 +  struct socket;
    1.49 +  struct sctp_rcvinfo;
    1.50 +}
    1.51 +
    1.52 +namespace mozilla {
    1.53 +
    1.54 +class DTLSConnection;
    1.55 +class DataChannelConnection;
    1.56 +class DataChannel;
    1.57 +class DataChannelOnMessageAvailable;
    1.58 +
    1.59 +// For queuing outgoing messages
    1.60 +class BufferedMsg
    1.61 +{
    1.62 +public:
    1.63 +  BufferedMsg(struct sctp_sendv_spa &spa,const char *data,
    1.64 +              uint32_t length);
    1.65 +  ~BufferedMsg();
    1.66 +
    1.67 +  struct sctp_sendv_spa *mSpa;
    1.68 +  const char *mData;
    1.69 +  uint32_t mLength;
    1.70 +};
    1.71 +
    1.72 +// for queuing incoming data messages before the Open or
    1.73 +// external negotiation is indicated to us
    1.74 +class QueuedDataMessage
    1.75 +{
    1.76 +public:
    1.77 +  QueuedDataMessage(uint16_t stream, uint32_t ppid,
    1.78 +             const void *data, size_t length)
    1.79 +    : mStream(stream)
    1.80 +    , mPpid(ppid)
    1.81 +    , mLength(length)
    1.82 +  {
    1.83 +    mData = static_cast<char *>(moz_xmalloc(length)); // infallible
    1.84 +    memcpy(mData, data, length);
    1.85 +  }
    1.86 +
    1.87 +  ~QueuedDataMessage()
    1.88 +  {
    1.89 +    moz_free(mData);
    1.90 +  }
    1.91 +
    1.92 +  uint16_t mStream;
    1.93 +  uint32_t mPpid;
    1.94 +  size_t   mLength;
    1.95 +  char     *mData;
    1.96 +};
    1.97 +
    1.98 +// One per PeerConnection
    1.99 +class DataChannelConnection: public nsITimerCallback
   1.100 +#ifdef SCTP_DTLS_SUPPORTED
   1.101 +                             , public sigslot::has_slots<>
   1.102 +#endif
   1.103 +{
   1.104 +public:
   1.105 +  NS_DECL_THREADSAFE_ISUPPORTS
   1.106 +  NS_DECL_NSITIMERCALLBACK
   1.107 +
   1.108 +  class DataConnectionListener : public SupportsWeakPtr<DataConnectionListener>
   1.109 +  {
   1.110 +  public:
   1.111 +    MOZ_DECLARE_REFCOUNTED_TYPENAME(DataChannelConnection::DataConnectionListener)
   1.112 +    virtual ~DataConnectionListener() {}
   1.113 +
   1.114 +    // Called when a the connection is open
   1.115 +    virtual void NotifyConnection() = 0;
   1.116 +
   1.117 +    // Called when a the connection is lost/closed
   1.118 +    virtual void NotifyClosedConnection() = 0;
   1.119 +
   1.120 +    // Called when a new DataChannel has been opened by the other side.
   1.121 +    virtual void NotifyDataChannel(already_AddRefed<DataChannel> channel) = 0;
   1.122 +  };
   1.123 +
   1.124 +  DataChannelConnection(DataConnectionListener *listener);
   1.125 +  virtual ~DataChannelConnection();
   1.126 +
   1.127 +  bool Init(unsigned short aPort, uint16_t aNumStreams, bool aUsingDtls);
   1.128 +  void Destroy(); // So we can spawn refs tied to runnables in shutdown
   1.129 +  // Finish Destroy on STS to avoid SCTP race condition with ABORT from far end
   1.130 +  void DestroyOnSTS(struct socket *aMasterSocket,
   1.131 +                    struct socket *aSocket);
   1.132 +
   1.133 +#ifdef ALLOW_DIRECT_SCTP_LISTEN_CONNECT
   1.134 +  // These block; they require something to decide on listener/connector
   1.135 +  // (though you can do simultaneous Connect()).  Do not call these from
   1.136 +  // the main thread!
   1.137 +  bool Listen(unsigned short port);
   1.138 +  bool Connect(const char *addr, unsigned short port);
   1.139 +#endif
   1.140 +
   1.141 +#ifdef SCTP_DTLS_SUPPORTED
   1.142 +  // Connect using a TransportFlow (DTLS) channel
   1.143 +  void SetEvenOdd();
   1.144 +  bool ConnectViaTransportFlow(TransportFlow *aFlow, uint16_t localport, uint16_t remoteport);
   1.145 +  void CompleteConnect(TransportFlow *flow, TransportLayer::State state);
   1.146 +  void SetSignals();
   1.147 +#endif
   1.148 +
   1.149 +  typedef enum {
   1.150 +    RELIABLE=0,
   1.151 +    PARTIAL_RELIABLE_REXMIT = 1,
   1.152 +    PARTIAL_RELIABLE_TIMED = 2
   1.153 +  } Type;
   1.154 +
   1.155 +  already_AddRefed<DataChannel> Open(const nsACString& label,
   1.156 +                                     const nsACString& protocol,
   1.157 +                                     Type type, bool inOrder,
   1.158 +                                     uint32_t prValue,
   1.159 +                                     DataChannelListener *aListener,
   1.160 +                                     nsISupports *aContext,
   1.161 +                                     bool aExternalNegotiated,
   1.162 +                                     uint16_t aStream) NS_WARN_UNUSED_RESULT;
   1.163 +
   1.164 +  void Close(DataChannel *aChannel);
   1.165 +  // CloseInt() must be called with mLock held
   1.166 +  void CloseInt(DataChannel *aChannel);
   1.167 +  void CloseAll();
   1.168 +
   1.169 +  int32_t SendMsg(uint16_t stream, const nsACString &aMsg)
   1.170 +    {
   1.171 +      return SendMsgCommon(stream, aMsg, false);
   1.172 +    }
   1.173 +  int32_t SendBinaryMsg(uint16_t stream, const nsACString &aMsg)
   1.174 +    {
   1.175 +      return SendMsgCommon(stream, aMsg, true);
   1.176 +    }
   1.177 +  int32_t SendBlob(uint16_t stream, nsIInputStream *aBlob);
   1.178 +
   1.179 +  // Called on data reception from the SCTP library
   1.180 +  // must(?) be public so my c->c++ trampoline can call it
   1.181 +  int ReceiveCallback(struct socket* sock, void *data, size_t datalen,
   1.182 +                      struct sctp_rcvinfo rcv, int32_t flags);
   1.183 +
   1.184 +  // Find out state
   1.185 +  enum {
   1.186 +    CONNECTING = 0U,
   1.187 +    OPEN = 1U,
   1.188 +    CLOSING = 2U,
   1.189 +    CLOSED = 3U
   1.190 +  };
   1.191 +  uint16_t GetReadyState() { MutexAutoLock lock(mLock); return mState; }
   1.192 +
   1.193 +  friend class DataChannel;
   1.194 +  Mutex  mLock;
   1.195 +
   1.196 +  void ReadBlob(already_AddRefed<DataChannelConnection> aThis, uint16_t aStream, nsIInputStream* aBlob);
   1.197 +
   1.198 +  void GetStreamIds(std::vector<uint16_t>* aStreamList);
   1.199 +
   1.200 +protected:
   1.201 +  friend class DataChannelOnMessageAvailable;
   1.202 +  // Avoid cycles with PeerConnectionImpl
   1.203 +  // Use from main thread only as WeakPtr is not threadsafe
   1.204 +  WeakPtr<DataConnectionListener> mListener;
   1.205 +
   1.206 +private:
   1.207 +  friend class DataChannelConnectRunnable;
   1.208 +
   1.209 +#ifdef SCTP_DTLS_SUPPORTED
   1.210 +  static void DTLSConnectThread(void *data);
   1.211 +  int SendPacket(const unsigned char* data, size_t len, bool release);
   1.212 +  void SctpDtlsInput(TransportFlow *flow, const unsigned char *data, size_t len);
   1.213 +  static int SctpDtlsOutput(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df);
   1.214 +#endif
   1.215 +  DataChannel* FindChannelByStream(uint16_t stream);
   1.216 +  uint16_t FindFreeStream();
   1.217 +  bool RequestMoreStreams(int32_t aNeeded = 16);
   1.218 +  int32_t SendControlMessage(void *msg, uint32_t len, uint16_t stream);
   1.219 +  int32_t SendOpenRequestMessage(const nsACString& label, const nsACString& protocol,
   1.220 +                                 uint16_t stream,
   1.221 +                                 bool unordered, uint16_t prPolicy, uint32_t prValue);
   1.222 +  int32_t SendOpenAckMessage(uint16_t stream);
   1.223 +  int32_t SendMsgInternal(DataChannel *channel, const char *data,
   1.224 +                          uint32_t length, uint32_t ppid);
   1.225 +  int32_t SendBinary(DataChannel *channel, const char *data,
   1.226 +                     uint32_t len, uint32_t ppid_partial, uint32_t ppid_final);
   1.227 +  int32_t SendMsgCommon(uint16_t stream, const nsACString &aMsg, bool isBinary);
   1.228 +
   1.229 +  void DeliverQueuedData(uint16_t stream);
   1.230 +
   1.231 +  already_AddRefed<DataChannel> OpenFinish(already_AddRefed<DataChannel>&& aChannel);
   1.232 +
   1.233 +  void StartDefer();
   1.234 +  bool SendDeferredMessages();
   1.235 +  void ProcessQueuedOpens();
   1.236 +  void ClearResets();
   1.237 +  void SendOutgoingStreamReset();
   1.238 +  void ResetOutgoingStream(uint16_t stream);
   1.239 +  void HandleOpenRequestMessage(const struct rtcweb_datachannel_open_request *req,
   1.240 +                                size_t length,
   1.241 +                                uint16_t stream);
   1.242 +  void HandleOpenAckMessage(const struct rtcweb_datachannel_ack *ack,
   1.243 +                            size_t length, uint16_t stream);
   1.244 +  void HandleUnknownMessage(uint32_t ppid, size_t length, uint16_t stream);
   1.245 +  void HandleDataMessage(uint32_t ppid, const void *buffer, size_t length, uint16_t stream);
   1.246 +  void HandleMessage(const void *buffer, size_t length, uint32_t ppid, uint16_t stream);
   1.247 +  void HandleAssociationChangeEvent(const struct sctp_assoc_change *sac);
   1.248 +  void HandlePeerAddressChangeEvent(const struct sctp_paddr_change *spc);
   1.249 +  void HandleRemoteErrorEvent(const struct sctp_remote_error *sre);
   1.250 +  void HandleShutdownEvent(const struct sctp_shutdown_event *sse);
   1.251 +  void HandleAdaptationIndication(const struct sctp_adaptation_event *sai);
   1.252 +  void HandleSendFailedEvent(const struct sctp_send_failed_event *ssfe);
   1.253 +  void HandleStreamResetEvent(const struct sctp_stream_reset_event *strrst);
   1.254 +  void HandleStreamChangeEvent(const struct sctp_stream_change_event *strchg);
   1.255 +  void HandleNotification(const union sctp_notification *notif, size_t n);
   1.256 +
   1.257 +#ifdef SCTP_DTLS_SUPPORTED
   1.258 +  bool IsSTSThread() {
   1.259 +    bool on = false;
   1.260 +    if (mSTS) {
   1.261 +      mSTS->IsOnCurrentThread(&on);
   1.262 +    }
   1.263 +    return on;
   1.264 +  }
   1.265 +#endif
   1.266 +
   1.267 +  // Exists solely for proxying release of the TransportFlow to the STS thread
   1.268 +  static void ReleaseTransportFlow(nsRefPtr<TransportFlow> aFlow) {}
   1.269 +
   1.270 +  // Data:
   1.271 +  // NOTE: while this array will auto-expand, increases in the number of
   1.272 +  // channels available from the stack must be negotiated!
   1.273 +  bool mAllocateEven;
   1.274 +  nsAutoTArray<nsRefPtr<DataChannel>,16> mStreams;
   1.275 +  nsDeque mPending; // Holds already_AddRefed<DataChannel>s -- careful!
   1.276 +  // holds data that's come in before a channel is open
   1.277 +  nsTArray<nsAutoPtr<QueuedDataMessage> > mQueuedData;
   1.278 +
   1.279 +  // Streams pending reset
   1.280 +  nsAutoTArray<uint16_t,4> mStreamsResetting;
   1.281 +
   1.282 +  struct socket *mMasterSocket; // accessed from STS thread
   1.283 +  struct socket *mSocket; // cloned from mMasterSocket on successful Connect on STS thread
   1.284 +  uint16_t mState; // Protected with mLock
   1.285 +
   1.286 +#ifdef SCTP_DTLS_SUPPORTED
   1.287 +  nsRefPtr<TransportFlow> mTransportFlow;
   1.288 +  nsCOMPtr<nsIEventTarget> mSTS;
   1.289 +#endif
   1.290 +  uint16_t mLocalPort; // Accessed from connect thread
   1.291 +  uint16_t mRemotePort;
   1.292 +  bool mUsingDtls;
   1.293 +
   1.294 +  // Timer to control when we try to resend blocked messages
   1.295 +  nsCOMPtr<nsITimer> mDeferredTimer;
   1.296 +  uint32_t mDeferTimeout; // in ms
   1.297 +  bool mTimerRunning;
   1.298 +  nsCOMPtr<nsIThread> mInternalIOThread;
   1.299 +};
   1.300 +
   1.301 +#define ENSURE_DATACONNECTION \
   1.302 +  do { if (!mConnection) { DATACHANNEL_LOG(("%s: %p no connection!",__FUNCTION__, this)); return; } } while (0)
   1.303 +
   1.304 +#define ENSURE_DATACONNECTION_RET(x) \
   1.305 +  do { if (!mConnection) { DATACHANNEL_LOG(("%s: %p no connection!",__FUNCTION__, this)); return (x); } } while (0)
   1.306 +
   1.307 +class DataChannel {
   1.308 +public:
   1.309 +  enum {
   1.310 +    CONNECTING = 0U,
   1.311 +    OPEN = 1U,
   1.312 +    CLOSING = 2U,
   1.313 +    CLOSED = 3U,
   1.314 +    WAITING_TO_OPEN = 4U
   1.315 +  };
   1.316 +
   1.317 +  DataChannel(DataChannelConnection *connection,
   1.318 +              uint16_t stream,
   1.319 +              uint16_t state,
   1.320 +              const nsACString& label,
   1.321 +              const nsACString& protocol,
   1.322 +              uint16_t policy, uint32_t value,
   1.323 +              uint32_t flags,
   1.324 +              DataChannelListener *aListener,
   1.325 +              nsISupports *aContext)
   1.326 +    : mListenerLock("netwerk::sctp::DataChannel")
   1.327 +    , mListener(aListener)
   1.328 +    , mContext(aContext)
   1.329 +    , mConnection(connection)
   1.330 +    , mLabel(label)
   1.331 +    , mProtocol(protocol)
   1.332 +    , mState(state)
   1.333 +    , mReady(false)
   1.334 +    , mStream(stream)
   1.335 +    , mPrPolicy(policy)
   1.336 +    , mPrValue(value)
   1.337 +    , mFlags(flags)
   1.338 +    , mIsRecvBinary(false)
   1.339 +    {
   1.340 +      NS_ASSERTION(mConnection,"NULL connection");
   1.341 +    }
   1.342 +
   1.343 +  ~DataChannel();
   1.344 +  void Destroy(); // when we disconnect from the connection after stream RESET
   1.345 +
   1.346 +  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataChannel)
   1.347 +
   1.348 +  // Close this DataChannel.  Can be called multiple times.  MUST be called
   1.349 +  // before destroying the DataChannel (state must be CLOSED or CLOSING).
   1.350 +  void Close();
   1.351 +
   1.352 +  // Set the listener (especially for channels created from the other side)
   1.353 +  void SetListener(DataChannelListener *aListener, nsISupports *aContext);
   1.354 +
   1.355 +  // Send a string
   1.356 +  bool SendMsg(const nsACString &aMsg)
   1.357 +    {
   1.358 +      ENSURE_DATACONNECTION_RET(false);
   1.359 +
   1.360 +      if (mStream != INVALID_STREAM)
   1.361 +        return (mConnection->SendMsg(mStream, aMsg) > 0);
   1.362 +      else
   1.363 +        return false;
   1.364 +    }
   1.365 +
   1.366 +  // Send a binary message (TypedArray)
   1.367 +  bool SendBinaryMsg(const nsACString &aMsg)
   1.368 +    {
   1.369 +      ENSURE_DATACONNECTION_RET(false);
   1.370 +
   1.371 +      if (mStream != INVALID_STREAM)
   1.372 +        return (mConnection->SendBinaryMsg(mStream, aMsg) > 0);
   1.373 +      else
   1.374 +        return false;
   1.375 +    }
   1.376 +
   1.377 +  // Send a binary blob
   1.378 +  bool SendBinaryStream(nsIInputStream *aBlob, uint32_t msgLen)
   1.379 +    {
   1.380 +      ENSURE_DATACONNECTION_RET(false);
   1.381 +
   1.382 +      if (mStream != INVALID_STREAM)
   1.383 +        return (mConnection->SendBlob(mStream, aBlob) > 0);
   1.384 +      else
   1.385 +        return false;
   1.386 +    }
   1.387 +
   1.388 +  uint16_t GetType() { return mPrPolicy; }
   1.389 +
   1.390 +  bool GetOrdered() { return !(mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED); }
   1.391 +
   1.392 +  // Amount of data buffered to send
   1.393 +  uint32_t GetBufferedAmount();
   1.394 +
   1.395 +  // Find out state
   1.396 +  uint16_t GetReadyState()
   1.397 +    {
   1.398 +      if (mConnection) {
   1.399 +        MutexAutoLock lock(mConnection->mLock);
   1.400 +        if (mState == WAITING_TO_OPEN)
   1.401 +          return CONNECTING;
   1.402 +        return mState;
   1.403 +      }
   1.404 +      return CLOSED;
   1.405 +    }
   1.406 +
   1.407 +  void GetLabel(nsAString& aLabel) { CopyUTF8toUTF16(mLabel, aLabel); }
   1.408 +  void GetProtocol(nsAString& aProtocol) { CopyUTF8toUTF16(mProtocol, aProtocol); }
   1.409 +  uint16_t GetStream() { return mStream; }
   1.410 +
   1.411 +  void AppReady();
   1.412 +
   1.413 +  void SendOrQueue(DataChannelOnMessageAvailable *aMessage);
   1.414 +
   1.415 +protected:
   1.416 +  Mutex mListenerLock; // protects mListener and mContext
   1.417 +  DataChannelListener *mListener;
   1.418 +  nsCOMPtr<nsISupports> mContext;
   1.419 +
   1.420 +private:
   1.421 +  friend class DataChannelOnMessageAvailable;
   1.422 +  friend class DataChannelConnection;
   1.423 +
   1.424 +  nsresult AddDataToBinaryMsg(const char *data, uint32_t size);
   1.425 +
   1.426 +  nsRefPtr<DataChannelConnection> mConnection;
   1.427 +  nsCString mLabel;
   1.428 +  nsCString mProtocol;
   1.429 +  uint16_t mState;
   1.430 +  bool     mReady;
   1.431 +  uint16_t mStream;
   1.432 +  uint16_t mPrPolicy;
   1.433 +  uint32_t mPrValue;
   1.434 +  uint32_t mFlags;
   1.435 +  uint32_t mId;
   1.436 +  bool mIsRecvBinary;
   1.437 +  nsCString mRecvBuffer;
   1.438 +  nsTArray<nsAutoPtr<BufferedMsg> > mBufferedData;
   1.439 +  nsTArray<nsCOMPtr<nsIRunnable> > mQueuedMessages;
   1.440 +};
   1.441 +
   1.442 +// used to dispatch notifications of incoming data to the main thread
   1.443 +// Patterned on CallOnMessageAvailable in WebSockets
   1.444 +// Also used to proxy other items to MainThread
   1.445 +class DataChannelOnMessageAvailable : public nsRunnable
   1.446 +{
   1.447 +public:
   1.448 +  enum {
   1.449 +    ON_CONNECTION,
   1.450 +    ON_DISCONNECTED,
   1.451 +    ON_CHANNEL_CREATED,
   1.452 +    ON_CHANNEL_OPEN,
   1.453 +    ON_CHANNEL_CLOSED,
   1.454 +    ON_DATA,
   1.455 +    START_DEFER,
   1.456 +  };  /* types */
   1.457 +
   1.458 +  DataChannelOnMessageAvailable(int32_t     aType,
   1.459 +                                DataChannelConnection *aConnection,
   1.460 +                                DataChannel *aChannel,
   1.461 +                                nsCString   &aData,  // XXX this causes inefficiency
   1.462 +                                int32_t     aLen)
   1.463 +    : mType(aType),
   1.464 +      mChannel(aChannel),
   1.465 +      mConnection(aConnection),
   1.466 +      mData(aData),
   1.467 +      mLen(aLen) {}
   1.468 +
   1.469 +  DataChannelOnMessageAvailable(int32_t     aType,
   1.470 +                                DataChannel *aChannel)
   1.471 +    : mType(aType),
   1.472 +      mChannel(aChannel) {}
   1.473 +  // XXX is it safe to leave mData/mLen uninitialized?  This should only be
   1.474 +  // used for notifications that don't use them, but I'd like more
   1.475 +  // bulletproof compile-time checking.
   1.476 +
   1.477 +  DataChannelOnMessageAvailable(int32_t     aType,
   1.478 +                                DataChannelConnection *aConnection,
   1.479 +                                DataChannel *aChannel)
   1.480 +    : mType(aType),
   1.481 +      mChannel(aChannel),
   1.482 +      mConnection(aConnection) {}
   1.483 +
   1.484 +  // for ON_CONNECTION/ON_DISCONNECTED
   1.485 +  DataChannelOnMessageAvailable(int32_t     aType,
   1.486 +                                DataChannelConnection *aConnection,
   1.487 +                                bool aResult = true)
   1.488 +    : mType(aType),
   1.489 +      mConnection(aConnection),
   1.490 +      mResult(aResult) {}
   1.491 +
   1.492 +  NS_IMETHOD Run()
   1.493 +  {
   1.494 +    MOZ_ASSERT(NS_IsMainThread());
   1.495 +    switch (mType) {
   1.496 +      case ON_DATA:
   1.497 +      case ON_CHANNEL_OPEN:
   1.498 +      case ON_CHANNEL_CLOSED:
   1.499 +        {
   1.500 +          MutexAutoLock lock(mChannel->mListenerLock);
   1.501 +          if (!mChannel->mListener) {
   1.502 +            DATACHANNEL_LOG(("DataChannelOnMessageAvailable (%d) with null Listener!",mType));
   1.503 +            return NS_OK;
   1.504 +          }
   1.505 +
   1.506 +          switch (mType) {
   1.507 +            case ON_DATA:
   1.508 +              if (mLen < 0) {
   1.509 +                mChannel->mListener->OnMessageAvailable(mChannel->mContext, mData);
   1.510 +              } else {
   1.511 +                mChannel->mListener->OnBinaryMessageAvailable(mChannel->mContext, mData);
   1.512 +              }
   1.513 +              break;
   1.514 +            case ON_CHANNEL_OPEN:
   1.515 +              mChannel->mListener->OnChannelConnected(mChannel->mContext);
   1.516 +              break;
   1.517 +            case ON_CHANNEL_CLOSED:
   1.518 +              mChannel->mListener->OnChannelClosed(mChannel->mContext);
   1.519 +              break;
   1.520 +          }
   1.521 +          break;
   1.522 +        }
   1.523 +      case ON_DISCONNECTED:
   1.524 +        // If we've disconnected, make sure we close all the streams - from mainthread!
   1.525 +        mConnection->CloseAll();
   1.526 +        // fall through
   1.527 +      case ON_CHANNEL_CREATED:
   1.528 +      case ON_CONNECTION:
   1.529 +        // WeakPtr - only used/modified/nulled from MainThread so we can use a WeakPtr here
   1.530 +        if (!mConnection->mListener) {
   1.531 +          DATACHANNEL_LOG(("DataChannelOnMessageAvailable (%d) with null Listener",mType));
   1.532 +          return NS_OK;
   1.533 +        }
   1.534 +        switch (mType) {
   1.535 +          case ON_CHANNEL_CREATED:
   1.536 +            // important to give it an already_AddRefed pointer!
   1.537 +            mConnection->mListener->NotifyDataChannel(mChannel.forget());
   1.538 +            break;
   1.539 +          case ON_CONNECTION:
   1.540 +            if (mResult) {
   1.541 +              mConnection->mListener->NotifyConnection();
   1.542 +            }
   1.543 +            // FIX - on mResult false (failure) we should do something.  Needs spec work here
   1.544 +            break;
   1.545 +          case ON_DISCONNECTED:
   1.546 +            mConnection->mListener->NotifyClosedConnection();
   1.547 +            break;
   1.548 +        }
   1.549 +        break;
   1.550 +      case START_DEFER:
   1.551 +        mConnection->StartDefer();
   1.552 +        break;
   1.553 +    }
   1.554 +    return NS_OK;
   1.555 +  }
   1.556 +
   1.557 +private:
   1.558 +  ~DataChannelOnMessageAvailable() {}
   1.559 +
   1.560 +  int32_t                           mType;
   1.561 +  // XXX should use union
   1.562 +  nsRefPtr<DataChannel>             mChannel;
   1.563 +  nsRefPtr<DataChannelConnection>   mConnection;
   1.564 +  nsCString                         mData;
   1.565 +  int32_t                           mLen;
   1.566 +  bool                              mResult;
   1.567 +};
   1.568 +
   1.569 +}
   1.570 +
   1.571 +#endif  // NETWERK_SCTP_DATACHANNEL_DATACHANNEL_H_

mercurial