1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/websocket/WebSocketChannel.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,297 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set sw=2 ts=8 et 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 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_net_WebSocketChannel_h 1.11 +#define mozilla_net_WebSocketChannel_h 1.12 + 1.13 +#include "nsISupports.h" 1.14 +#include "nsIInterfaceRequestor.h" 1.15 +#include "nsIStreamListener.h" 1.16 +#include "nsIAsyncInputStream.h" 1.17 +#include "nsIAsyncOutputStream.h" 1.18 +#include "nsITimer.h" 1.19 +#include "nsIDNSListener.h" 1.20 +#include "nsIProtocolProxyCallback.h" 1.21 +#include "nsIChannelEventSink.h" 1.22 +#include "nsIHttpChannelInternal.h" 1.23 +#include "BaseWebSocketChannel.h" 1.24 + 1.25 +#ifdef MOZ_WIDGET_GONK 1.26 +#include "nsINetworkManager.h" 1.27 +#include "nsProxyRelease.h" 1.28 +#endif 1.29 + 1.30 +#include "nsCOMPtr.h" 1.31 +#include "nsString.h" 1.32 +#include "nsDeque.h" 1.33 + 1.34 +class nsIAsyncVerifyRedirectCallback; 1.35 +class nsIDashboardEventNotifier; 1.36 +class nsIEventTarget; 1.37 +class nsIHttpChannel; 1.38 +class nsIRandomGenerator; 1.39 +class nsISocketTransport; 1.40 +class nsIURI; 1.41 + 1.42 +namespace mozilla { namespace net { 1.43 + 1.44 +class OutboundMessage; 1.45 +class OutboundEnqueuer; 1.46 +class nsWSAdmissionManager; 1.47 +class nsWSCompression; 1.48 +class CallOnMessageAvailable; 1.49 +class CallOnStop; 1.50 +class CallOnServerClose; 1.51 +class CallAcknowledge; 1.52 + 1.53 +// Used to enforce "1 connecting websocket per host" rule, and reconnect delays 1.54 +enum wsConnectingState { 1.55 + NOT_CONNECTING = 0, // Not yet (or no longer) trying to open connection 1.56 + CONNECTING_QUEUED, // Waiting for other ws to same host to finish opening 1.57 + CONNECTING_DELAYED, // Delayed by "reconnect after failure" algorithm 1.58 + CONNECTING_IN_PROGRESS // Started connection: waiting for result 1.59 +}; 1.60 + 1.61 +class WebSocketChannel : public BaseWebSocketChannel, 1.62 + public nsIHttpUpgradeListener, 1.63 + public nsIStreamListener, 1.64 + public nsIInputStreamCallback, 1.65 + public nsIOutputStreamCallback, 1.66 + public nsITimerCallback, 1.67 + public nsIDNSListener, 1.68 + public nsIProtocolProxyCallback, 1.69 + public nsIInterfaceRequestor, 1.70 + public nsIChannelEventSink 1.71 +{ 1.72 +public: 1.73 + NS_DECL_THREADSAFE_ISUPPORTS 1.74 + NS_DECL_NSIHTTPUPGRADELISTENER 1.75 + NS_DECL_NSIREQUESTOBSERVER 1.76 + NS_DECL_NSISTREAMLISTENER 1.77 + NS_DECL_NSIINPUTSTREAMCALLBACK 1.78 + NS_DECL_NSIOUTPUTSTREAMCALLBACK 1.79 + NS_DECL_NSITIMERCALLBACK 1.80 + NS_DECL_NSIDNSLISTENER 1.81 + NS_DECL_NSIPROTOCOLPROXYCALLBACK 1.82 + NS_DECL_NSIINTERFACEREQUESTOR 1.83 + NS_DECL_NSICHANNELEVENTSINK 1.84 + 1.85 + // nsIWebSocketChannel methods BaseWebSocketChannel didn't implement for us 1.86 + // 1.87 + NS_IMETHOD AsyncOpen(nsIURI *aURI, 1.88 + const nsACString &aOrigin, 1.89 + nsIWebSocketListener *aListener, 1.90 + nsISupports *aContext); 1.91 + NS_IMETHOD Close(uint16_t aCode, const nsACString & aReason); 1.92 + NS_IMETHOD SendMsg(const nsACString &aMsg); 1.93 + NS_IMETHOD SendBinaryMsg(const nsACString &aMsg); 1.94 + NS_IMETHOD SendBinaryStream(nsIInputStream *aStream, uint32_t length); 1.95 + NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo); 1.96 + 1.97 + WebSocketChannel(); 1.98 + static void Shutdown(); 1.99 + 1.100 + enum { 1.101 + // Non Control Frames 1.102 + kContinuation = 0x0, 1.103 + kText = 0x1, 1.104 + kBinary = 0x2, 1.105 + 1.106 + // Control Frames 1.107 + kClose = 0x8, 1.108 + kPing = 0x9, 1.109 + kPong = 0xA 1.110 + }; 1.111 + 1.112 + const static uint32_t kControlFrameMask = 0x8; 1.113 + const static uint8_t kMaskBit = 0x80; 1.114 + const static uint8_t kFinalFragBit = 0x80; 1.115 + 1.116 +protected: 1.117 + virtual ~WebSocketChannel(); 1.118 + 1.119 +private: 1.120 + friend class OutboundEnqueuer; 1.121 + friend class nsWSAdmissionManager; 1.122 + friend class FailDelayManager; 1.123 + friend class CallOnMessageAvailable; 1.124 + friend class CallOnStop; 1.125 + friend class CallOnServerClose; 1.126 + friend class CallAcknowledge; 1.127 + 1.128 + // Common send code for binary + text msgs 1.129 + nsresult SendMsgCommon(const nsACString *aMsg, bool isBinary, 1.130 + uint32_t length, nsIInputStream *aStream = nullptr); 1.131 + 1.132 + void EnqueueOutgoingMessage(nsDeque &aQueue, OutboundMessage *aMsg); 1.133 + 1.134 + void PrimeNewOutgoingMessage(); 1.135 + void DeleteCurrentOutGoingMessage(); 1.136 + void GeneratePong(uint8_t *payload, uint32_t len); 1.137 + void GeneratePing(); 1.138 + 1.139 + void BeginOpen(); 1.140 + nsresult HandleExtensions(); 1.141 + nsresult SetupRequest(); 1.142 + nsresult ApplyForAdmission(); 1.143 + nsresult DoAdmissionDNS(); 1.144 + nsresult StartWebsocketData(); 1.145 + uint16_t ResultToCloseCode(nsresult resultCode); 1.146 + void ReportConnectionTelemetry(); 1.147 + 1.148 + void StopSession(nsresult reason); 1.149 + void AbortSession(nsresult reason); 1.150 + void ReleaseSession(); 1.151 + void CleanupConnection(); 1.152 + void IncrementSessionCount(); 1.153 + void DecrementSessionCount(); 1.154 + 1.155 + void EnsureHdrOut(uint32_t size); 1.156 + void ApplyMask(uint32_t mask, uint8_t *data, uint64_t len); 1.157 + 1.158 + bool IsPersistentFramePtr(); 1.159 + nsresult ProcessInput(uint8_t *buffer, uint32_t count); 1.160 + bool UpdateReadBuffer(uint8_t *buffer, uint32_t count, 1.161 + uint32_t accumulatedFragments, 1.162 + uint32_t *available); 1.163 + 1.164 + inline void ResetPingTimer() 1.165 + { 1.166 + if (mPingTimer) { 1.167 + mPingOutstanding = 0; 1.168 + mPingTimer->SetDelay(mPingInterval); 1.169 + } 1.170 + } 1.171 + 1.172 + nsCOMPtr<nsIEventTarget> mSocketThread; 1.173 + nsCOMPtr<nsIHttpChannelInternal> mChannel; 1.174 + nsCOMPtr<nsIHttpChannel> mHttpChannel; 1.175 + nsCOMPtr<nsICancelable> mCancelable; 1.176 + nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback; 1.177 + nsCOMPtr<nsIRandomGenerator> mRandomGenerator; 1.178 + 1.179 + nsCString mHashedSecret; 1.180 + 1.181 + // Used as key for connection managment: Initially set to hostname from URI, 1.182 + // then to IP address (unless we're leaving DNS resolution to a proxy server) 1.183 + nsCString mAddress; 1.184 + int32_t mPort; // WS server port 1.185 + 1.186 + // Used for off main thread access to the URI string. 1.187 + nsCString mHost; 1.188 + 1.189 + nsCOMPtr<nsISocketTransport> mTransport; 1.190 + nsCOMPtr<nsIAsyncInputStream> mSocketIn; 1.191 + nsCOMPtr<nsIAsyncOutputStream> mSocketOut; 1.192 + 1.193 + nsCOMPtr<nsITimer> mCloseTimer; 1.194 + uint32_t mCloseTimeout; /* milliseconds */ 1.195 + 1.196 + nsCOMPtr<nsITimer> mOpenTimer; 1.197 + uint32_t mOpenTimeout; /* milliseconds */ 1.198 + wsConnectingState mConnecting; /* 0 if not connecting */ 1.199 + nsCOMPtr<nsITimer> mReconnectDelayTimer; 1.200 + 1.201 + nsCOMPtr<nsITimer> mPingTimer; 1.202 + 1.203 + nsCOMPtr<nsITimer> mLingeringCloseTimer; 1.204 + const static int32_t kLingeringCloseTimeout = 1000; 1.205 + const static int32_t kLingeringCloseThreshold = 50; 1.206 + 1.207 + int32_t mMaxConcurrentConnections; 1.208 + 1.209 + uint32_t mGotUpgradeOK : 1; 1.210 + uint32_t mRecvdHttpUpgradeTransport : 1; 1.211 + uint32_t mRequestedClose : 1; 1.212 + uint32_t mClientClosed : 1; 1.213 + uint32_t mServerClosed : 1; 1.214 + uint32_t mStopped : 1; 1.215 + uint32_t mCalledOnStop : 1; 1.216 + uint32_t mPingOutstanding : 1; 1.217 + uint32_t mAllowCompression : 1; 1.218 + uint32_t mAutoFollowRedirects : 1; 1.219 + uint32_t mReleaseOnTransmit : 1; 1.220 + uint32_t mTCPClosed : 1; 1.221 + uint32_t mOpenedHttpChannel : 1; 1.222 + uint32_t mDataStarted : 1; 1.223 + uint32_t mIncrementedSessionCount : 1; 1.224 + uint32_t mDecrementedSessionCount : 1; 1.225 + 1.226 + int32_t mMaxMessageSize; 1.227 + nsresult mStopOnClose; 1.228 + uint16_t mServerCloseCode; 1.229 + nsCString mServerCloseReason; 1.230 + uint16_t mScriptCloseCode; 1.231 + nsCString mScriptCloseReason; 1.232 + 1.233 + // These are for the read buffers 1.234 + const static uint32_t kIncomingBufferInitialSize = 16 * 1024; 1.235 + // We're ok with keeping a buffer this size or smaller around for the life of 1.236 + // the websocket. If a particular message needs bigger than this we'll 1.237 + // increase the buffer temporarily, then drop back down to this size. 1.238 + const static uint32_t kIncomingBufferStableSize = 128 * 1024; 1.239 + 1.240 + uint8_t *mFramePtr; 1.241 + uint8_t *mBuffer; 1.242 + uint8_t mFragmentOpcode; 1.243 + uint32_t mFragmentAccumulator; 1.244 + uint32_t mBuffered; 1.245 + uint32_t mBufferSize; 1.246 + nsCOMPtr<nsIStreamListener> mInflateReader; 1.247 + nsCOMPtr<nsIStringInputStream> mInflateStream; 1.248 + 1.249 + // These are for the send buffers 1.250 + const static int32_t kCopyBreak = 1000; 1.251 + 1.252 + OutboundMessage *mCurrentOut; 1.253 + uint32_t mCurrentOutSent; 1.254 + nsDeque mOutgoingMessages; 1.255 + nsDeque mOutgoingPingMessages; 1.256 + nsDeque mOutgoingPongMessages; 1.257 + uint32_t mHdrOutToSend; 1.258 + uint8_t *mHdrOut; 1.259 + uint8_t mOutHeader[kCopyBreak + 16]; 1.260 + nsWSCompression *mCompressor; 1.261 + uint32_t mDynamicOutputSize; 1.262 + uint8_t *mDynamicOutput; 1.263 + bool mPrivateBrowsing; 1.264 + 1.265 + nsCOMPtr<nsIDashboardEventNotifier> mConnectionLogService; 1.266 + uint32_t mSerial; 1.267 + static uint32_t sSerialSeed; 1.268 + 1.269 +// These members are used for network per-app metering (bug 855949) 1.270 +// Currently, they are only available on gonk. 1.271 + uint64_t mCountRecv; 1.272 + uint64_t mCountSent; 1.273 + uint32_t mAppId; 1.274 +#ifdef MOZ_WIDGET_GONK 1.275 + nsMainThreadPtrHandle<nsINetworkInterface> mActiveNetwork; 1.276 +#endif 1.277 + nsresult SaveNetworkStats(bool); 1.278 + void CountRecvBytes(uint64_t recvBytes) 1.279 + { 1.280 + mCountRecv += recvBytes; 1.281 + SaveNetworkStats(false); 1.282 + } 1.283 + void CountSentBytes(uint64_t sentBytes) 1.284 + { 1.285 + mCountSent += sentBytes; 1.286 + SaveNetworkStats(false); 1.287 + } 1.288 +}; 1.289 + 1.290 +class WebSocketSSLChannel : public WebSocketChannel 1.291 +{ 1.292 +public: 1.293 + WebSocketSSLChannel() { BaseWebSocketChannel::mEncrypted = true; } 1.294 +protected: 1.295 + virtual ~WebSocketSSLChannel() {} 1.296 +}; 1.297 + 1.298 +}} // namespace mozilla::net 1.299 + 1.300 +#endif // mozilla_net_WebSocketChannel_h