1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/base/src/nsSocketTransport2.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,422 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifndef nsSocketTransport2_h__ 1.9 +#define nsSocketTransport2_h__ 1.10 + 1.11 +#ifdef DEBUG_darinf 1.12 +#define ENABLE_SOCKET_TRACING 1.13 +#endif 1.14 + 1.15 +#include "mozilla/Mutex.h" 1.16 +#include "nsSocketTransportService2.h" 1.17 +#include "nsString.h" 1.18 +#include "nsCOMPtr.h" 1.19 + 1.20 +#include "nsISocketTransport.h" 1.21 +#include "nsIAsyncInputStream.h" 1.22 +#include "nsIAsyncOutputStream.h" 1.23 +#include "nsIDNSListener.h" 1.24 +#include "nsIClassInfo.h" 1.25 +#include "mozilla/net/DNS.h" 1.26 +#include "nsASocketHandler.h" 1.27 + 1.28 +#include "prerror.h" 1.29 +#include "nsAutoPtr.h" 1.30 + 1.31 +class nsSocketTransport; 1.32 +class nsICancelable; 1.33 +class nsIDNSRecord; 1.34 +class nsIInterfaceRequestor; 1.35 + 1.36 +nsresult 1.37 +ErrorAccordingToNSPR(PRErrorCode errorCode); 1.38 + 1.39 +//----------------------------------------------------------------------------- 1.40 + 1.41 +// after this short interval, we will return to PR_Poll 1.42 +#define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20) 1.43 + 1.44 +//----------------------------------------------------------------------------- 1.45 + 1.46 +class nsSocketInputStream : public nsIAsyncInputStream 1.47 +{ 1.48 +public: 1.49 + NS_DECL_ISUPPORTS_INHERITED 1.50 + NS_DECL_NSIINPUTSTREAM 1.51 + NS_DECL_NSIASYNCINPUTSTREAM 1.52 + 1.53 + nsSocketInputStream(nsSocketTransport *); 1.54 + virtual ~nsSocketInputStream(); 1.55 + 1.56 + bool IsReferenced() { return mReaderRefCnt > 0; } 1.57 + nsresult Condition() { return mCondition; } 1.58 + uint64_t ByteCount() { return mByteCount; } 1.59 + 1.60 + // called by the socket transport on the socket thread... 1.61 + void OnSocketReady(nsresult condition); 1.62 + 1.63 +private: 1.64 + nsSocketTransport *mTransport; 1.65 + mozilla::ThreadSafeAutoRefCnt mReaderRefCnt; 1.66 + 1.67 + // access to these is protected by mTransport->mLock 1.68 + nsresult mCondition; 1.69 + nsCOMPtr<nsIInputStreamCallback> mCallback; 1.70 + uint32_t mCallbackFlags; 1.71 + uint64_t mByteCount; 1.72 +}; 1.73 + 1.74 +//----------------------------------------------------------------------------- 1.75 + 1.76 +class nsSocketOutputStream : public nsIAsyncOutputStream 1.77 +{ 1.78 +public: 1.79 + NS_DECL_ISUPPORTS_INHERITED 1.80 + NS_DECL_NSIOUTPUTSTREAM 1.81 + NS_DECL_NSIASYNCOUTPUTSTREAM 1.82 + 1.83 + nsSocketOutputStream(nsSocketTransport *); 1.84 + virtual ~nsSocketOutputStream(); 1.85 + 1.86 + bool IsReferenced() { return mWriterRefCnt > 0; } 1.87 + nsresult Condition() { return mCondition; } 1.88 + uint64_t ByteCount() { return mByteCount; } 1.89 + 1.90 + // called by the socket transport on the socket thread... 1.91 + void OnSocketReady(nsresult condition); 1.92 + 1.93 +private: 1.94 + static NS_METHOD WriteFromSegments(nsIInputStream *, void *, 1.95 + const char *, uint32_t offset, 1.96 + uint32_t count, uint32_t *countRead); 1.97 + 1.98 + nsSocketTransport *mTransport; 1.99 + mozilla::ThreadSafeAutoRefCnt mWriterRefCnt; 1.100 + 1.101 + // access to these is protected by mTransport->mLock 1.102 + nsresult mCondition; 1.103 + nsCOMPtr<nsIOutputStreamCallback> mCallback; 1.104 + uint32_t mCallbackFlags; 1.105 + uint64_t mByteCount; 1.106 +}; 1.107 + 1.108 +//----------------------------------------------------------------------------- 1.109 + 1.110 +class nsSocketTransport : public nsASocketHandler 1.111 + , public nsISocketTransport 1.112 + , public nsIDNSListener 1.113 + , public nsIClassInfo 1.114 +{ 1.115 + typedef mozilla::Mutex Mutex; 1.116 + 1.117 +public: 1.118 + NS_DECL_THREADSAFE_ISUPPORTS 1.119 + NS_DECL_NSITRANSPORT 1.120 + NS_DECL_NSISOCKETTRANSPORT 1.121 + NS_DECL_NSIDNSLISTENER 1.122 + NS_DECL_NSICLASSINFO 1.123 + 1.124 + nsSocketTransport(); 1.125 + 1.126 + // this method instructs the socket transport to open a socket of the 1.127 + // given type(s) to the given host or proxy. 1.128 + nsresult Init(const char **socketTypes, uint32_t typeCount, 1.129 + const nsACString &host, uint16_t port, 1.130 + nsIProxyInfo *proxyInfo); 1.131 + 1.132 + // this method instructs the socket transport to use an already connected 1.133 + // socket with the given address. 1.134 + nsresult InitWithConnectedSocket(PRFileDesc *socketFD, 1.135 + const mozilla::net::NetAddr *addr); 1.136 + 1.137 + // This method instructs the socket transport to open a socket 1.138 + // connected to the given Unix domain address. We can only create 1.139 + // unlayered, simple, stream sockets. 1.140 + nsresult InitWithFilename(const char *filename); 1.141 + 1.142 + // nsASocketHandler methods: 1.143 + void OnSocketReady(PRFileDesc *, int16_t outFlags); 1.144 + void OnSocketDetached(PRFileDesc *); 1.145 + void IsLocal(bool *aIsLocal); 1.146 + void OnKeepaliveEnabledPrefChange(bool aEnabled) MOZ_OVERRIDE MOZ_FINAL; 1.147 + 1.148 + // called when a socket event is handled 1.149 + void OnSocketEvent(uint32_t type, nsresult status, nsISupports *param); 1.150 + 1.151 + uint64_t ByteCountReceived() { return mInput.ByteCount(); } 1.152 + uint64_t ByteCountSent() { return mOutput.ByteCount(); } 1.153 +protected: 1.154 + 1.155 + virtual ~nsSocketTransport(); 1.156 + 1.157 +private: 1.158 + 1.159 + // event types 1.160 + enum { 1.161 + MSG_ENSURE_CONNECT, 1.162 + MSG_DNS_LOOKUP_COMPLETE, 1.163 + MSG_RETRY_INIT_SOCKET, 1.164 + MSG_TIMEOUT_CHANGED, 1.165 + MSG_INPUT_CLOSED, 1.166 + MSG_INPUT_PENDING, 1.167 + MSG_OUTPUT_CLOSED, 1.168 + MSG_OUTPUT_PENDING 1.169 + }; 1.170 + nsresult PostEvent(uint32_t type, nsresult status = NS_OK, nsISupports *param = nullptr); 1.171 + 1.172 + enum { 1.173 + STATE_CLOSED, 1.174 + STATE_IDLE, 1.175 + STATE_RESOLVING, 1.176 + STATE_CONNECTING, 1.177 + STATE_TRANSFERRING, 1.178 + STATE_SENDINGGET, 1.179 + STATE_SENTGET 1.180 + }; 1.181 + 1.182 + // Safer way to get and automatically release PRFileDesc objects. 1.183 + class MOZ_STACK_CLASS PRFileDescAutoLock 1.184 + { 1.185 + public: 1.186 + typedef mozilla::MutexAutoLock MutexAutoLock; 1.187 + 1.188 + PRFileDescAutoLock(nsSocketTransport *aSocketTransport, 1.189 + nsresult *aConditionWhileLocked = nullptr) 1.190 + : mSocketTransport(aSocketTransport) 1.191 + , mFd(nullptr) 1.192 + { 1.193 + MOZ_ASSERT(aSocketTransport); 1.194 + MutexAutoLock lock(mSocketTransport->mLock); 1.195 + if (aConditionWhileLocked) { 1.196 + *aConditionWhileLocked = mSocketTransport->mCondition; 1.197 + if (NS_FAILED(mSocketTransport->mCondition)) { 1.198 + return; 1.199 + } 1.200 + } 1.201 + mFd = mSocketTransport->GetFD_Locked(); 1.202 + } 1.203 + ~PRFileDescAutoLock() { 1.204 + MutexAutoLock lock(mSocketTransport->mLock); 1.205 + if (mFd) { 1.206 + mSocketTransport->ReleaseFD_Locked(mFd); 1.207 + } 1.208 + } 1.209 + bool IsInitialized() { 1.210 + return mFd; 1.211 + } 1.212 + operator PRFileDesc*() { 1.213 + return mFd; 1.214 + } 1.215 + nsresult SetKeepaliveEnabled(bool aEnable); 1.216 + nsresult SetKeepaliveVals(bool aEnabled, int aIdleTime, 1.217 + int aRetryInterval, int aProbeCount); 1.218 + private: 1.219 + operator PRFileDescAutoLock*() { return nullptr; } 1.220 + 1.221 + // Weak ptr to nsSocketTransport since this is a stack class only. 1.222 + nsSocketTransport *mSocketTransport; 1.223 + PRFileDesc *mFd; 1.224 + }; 1.225 + friend class PRFileDescAutoLock; 1.226 + 1.227 + class LockedPRFileDesc 1.228 + { 1.229 + public: 1.230 + LockedPRFileDesc(nsSocketTransport *aSocketTransport) 1.231 + : mSocketTransport(aSocketTransport) 1.232 + , mFd(nullptr) 1.233 + { 1.234 + MOZ_ASSERT(aSocketTransport); 1.235 + } 1.236 + ~LockedPRFileDesc() {} 1.237 + bool IsInitialized() { 1.238 + return mFd; 1.239 + } 1.240 + LockedPRFileDesc& operator=(PRFileDesc *aFd) { 1.241 + mSocketTransport->mLock.AssertCurrentThreadOwns(); 1.242 + mFd = aFd; 1.243 + return *this; 1.244 + } 1.245 + operator PRFileDesc*() { 1.246 + if (mSocketTransport->mAttached) { 1.247 + mSocketTransport->mLock.AssertCurrentThreadOwns(); 1.248 + } 1.249 + return mFd; 1.250 + } 1.251 + bool operator==(PRFileDesc *aFd) { 1.252 + mSocketTransport->mLock.AssertCurrentThreadOwns(); 1.253 + return mFd == aFd; 1.254 + } 1.255 + private: 1.256 + operator LockedPRFileDesc*() { return nullptr; } 1.257 + // Weak ptr to nsSocketTransport since it owns this class. 1.258 + nsSocketTransport *mSocketTransport; 1.259 + PRFileDesc *mFd; 1.260 + }; 1.261 + friend class LockedPRFileDesc; 1.262 + 1.263 + //------------------------------------------------------------------------- 1.264 + // these members are "set" at initialization time and are never modified 1.265 + // afterwards. this allows them to be safely accessed from any thread. 1.266 + //------------------------------------------------------------------------- 1.267 + 1.268 + // socket type info: 1.269 + char **mTypes; 1.270 + uint32_t mTypeCount; 1.271 + nsCString mHost; 1.272 + uint16_t mPort; 1.273 + bool mHttpsProxy; 1.274 + 1.275 + nsCOMPtr<nsIProxyInfo> mProxyInfo; 1.276 + bool mProxyUse; 1.277 + bool mProxyTransparent; 1.278 + bool mProxyTransparentResolvesHost; 1.279 + uint32_t mConnectionFlags; 1.280 + 1.281 + uint16_t SocketPort(); 1.282 + const nsCString &SocketHost(); 1.283 + nsCString mProxyHostCache; // for SocketHost() only 1.284 + 1.285 + //------------------------------------------------------------------------- 1.286 + // members accessible only on the socket transport thread: 1.287 + // (the exception being initialization/shutdown time) 1.288 + //------------------------------------------------------------------------- 1.289 + 1.290 + // socket state vars: 1.291 + uint32_t mState; // STATE_??? flags 1.292 + bool mAttached; 1.293 + bool mInputClosed; 1.294 + bool mOutputClosed; 1.295 + 1.296 + // this flag is used to determine if the results of a host lookup arrive 1.297 + // recursively or not. this flag is not protected by any lock. 1.298 + bool mResolving; 1.299 + 1.300 + nsCOMPtr<nsICancelable> mDNSRequest; 1.301 + nsCOMPtr<nsIDNSRecord> mDNSRecord; 1.302 + 1.303 + // mNetAddr is valid from GetPeerAddr() once we have 1.304 + // reached STATE_TRANSFERRING. It must not change after that. 1.305 + mozilla::net::NetAddr mNetAddr; 1.306 + bool mNetAddrIsSet; 1.307 + 1.308 + // socket methods (these can only be called on the socket thread): 1.309 + 1.310 + void SendStatus(nsresult status); 1.311 + nsresult ResolveHost(); 1.312 + nsresult BuildSocket(PRFileDesc *&, bool &, bool &); 1.313 + nsresult InitiateSocket(); 1.314 + bool RecoverFromError(); 1.315 + 1.316 + void OnMsgInputPending() 1.317 + { 1.318 + if (mState == STATE_TRANSFERRING) 1.319 + mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT); 1.320 + } 1.321 + void OnMsgOutputPending() 1.322 + { 1.323 + if (mState == STATE_TRANSFERRING) 1.324 + mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT); 1.325 + } 1.326 + void OnMsgInputClosed(nsresult reason); 1.327 + void OnMsgOutputClosed(nsresult reason); 1.328 + 1.329 + // called when the socket is connected 1.330 + void OnSocketConnected(); 1.331 + 1.332 + //------------------------------------------------------------------------- 1.333 + // socket input/output objects. these may be accessed on any thread with 1.334 + // the exception of some specific methods (XXX). 1.335 + 1.336 + Mutex mLock; // protects members in this section. 1.337 + LockedPRFileDesc mFD; 1.338 + nsrefcnt mFDref; // mFD is closed when mFDref goes to zero. 1.339 + bool mFDconnected; // mFD is available to consumer when TRUE. 1.340 + 1.341 + // A delete protector reference to gSocketTransportService held for lifetime 1.342 + // of 'this'. Sometimes used interchangably with gSocketTransportService due 1.343 + // to scoping. 1.344 + nsRefPtr<nsSocketTransportService> mSocketTransportService; 1.345 + 1.346 + nsCOMPtr<nsIInterfaceRequestor> mCallbacks; 1.347 + nsCOMPtr<nsITransportEventSink> mEventSink; 1.348 + nsCOMPtr<nsISupports> mSecInfo; 1.349 + 1.350 + nsSocketInputStream mInput; 1.351 + nsSocketOutputStream mOutput; 1.352 + 1.353 + friend class nsSocketInputStream; 1.354 + friend class nsSocketOutputStream; 1.355 + 1.356 + // socket timeouts are not protected by any lock. 1.357 + uint16_t mTimeouts[2]; 1.358 + 1.359 + // QoS setting for socket 1.360 + uint8_t mQoSBits; 1.361 + 1.362 + // 1.363 + // mFD access methods: called with mLock held. 1.364 + // 1.365 + PRFileDesc *GetFD_Locked(); 1.366 + void ReleaseFD_Locked(PRFileDesc *fd); 1.367 + 1.368 + // 1.369 + // stream state changes (called outside mLock): 1.370 + // 1.371 + void OnInputClosed(nsresult reason) 1.372 + { 1.373 + // no need to post an event if called on the socket thread 1.374 + if (PR_GetCurrentThread() == gSocketThread) 1.375 + OnMsgInputClosed(reason); 1.376 + else 1.377 + PostEvent(MSG_INPUT_CLOSED, reason); 1.378 + } 1.379 + void OnInputPending() 1.380 + { 1.381 + // no need to post an event if called on the socket thread 1.382 + if (PR_GetCurrentThread() == gSocketThread) 1.383 + OnMsgInputPending(); 1.384 + else 1.385 + PostEvent(MSG_INPUT_PENDING); 1.386 + } 1.387 + void OnOutputClosed(nsresult reason) 1.388 + { 1.389 + // no need to post an event if called on the socket thread 1.390 + if (PR_GetCurrentThread() == gSocketThread) 1.391 + OnMsgOutputClosed(reason); // XXX need to not be inside lock! 1.392 + else 1.393 + PostEvent(MSG_OUTPUT_CLOSED, reason); 1.394 + } 1.395 + void OnOutputPending() 1.396 + { 1.397 + // no need to post an event if called on the socket thread 1.398 + if (PR_GetCurrentThread() == gSocketThread) 1.399 + OnMsgOutputPending(); 1.400 + else 1.401 + PostEvent(MSG_OUTPUT_PENDING); 1.402 + } 1.403 + 1.404 +#ifdef ENABLE_SOCKET_TRACING 1.405 + void TraceInBuf(const char *buf, int32_t n); 1.406 + void TraceOutBuf(const char *buf, int32_t n); 1.407 +#endif 1.408 + 1.409 + // Reads prefs to get default keepalive config. 1.410 + nsresult EnsureKeepaliveValsAreInitialized(); 1.411 + 1.412 + // Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals. 1.413 + nsresult SetKeepaliveEnabledInternal(bool aEnable); 1.414 + 1.415 + // True if keepalive has been enabled by the socket owner. Note: Keepalive 1.416 + // must also be enabled globally for it to be enabled in TCP. 1.417 + bool mKeepaliveEnabled; 1.418 + 1.419 + // Keepalive config (support varies by platform). 1.420 + int32_t mKeepaliveIdleTimeS; 1.421 + int32_t mKeepaliveRetryIntervalS; 1.422 + int32_t mKeepaliveProbeCount; 1.423 +}; 1.424 + 1.425 +#endif // !nsSocketTransport_h__