|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #ifndef nsSocketTransport2_h__ |
|
6 #define nsSocketTransport2_h__ |
|
7 |
|
8 #ifdef DEBUG_darinf |
|
9 #define ENABLE_SOCKET_TRACING |
|
10 #endif |
|
11 |
|
12 #include "mozilla/Mutex.h" |
|
13 #include "nsSocketTransportService2.h" |
|
14 #include "nsString.h" |
|
15 #include "nsCOMPtr.h" |
|
16 |
|
17 #include "nsISocketTransport.h" |
|
18 #include "nsIAsyncInputStream.h" |
|
19 #include "nsIAsyncOutputStream.h" |
|
20 #include "nsIDNSListener.h" |
|
21 #include "nsIClassInfo.h" |
|
22 #include "mozilla/net/DNS.h" |
|
23 #include "nsASocketHandler.h" |
|
24 |
|
25 #include "prerror.h" |
|
26 #include "nsAutoPtr.h" |
|
27 |
|
28 class nsSocketTransport; |
|
29 class nsICancelable; |
|
30 class nsIDNSRecord; |
|
31 class nsIInterfaceRequestor; |
|
32 |
|
33 nsresult |
|
34 ErrorAccordingToNSPR(PRErrorCode errorCode); |
|
35 |
|
36 //----------------------------------------------------------------------------- |
|
37 |
|
38 // after this short interval, we will return to PR_Poll |
|
39 #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20) |
|
40 |
|
41 //----------------------------------------------------------------------------- |
|
42 |
|
43 class nsSocketInputStream : public nsIAsyncInputStream |
|
44 { |
|
45 public: |
|
46 NS_DECL_ISUPPORTS_INHERITED |
|
47 NS_DECL_NSIINPUTSTREAM |
|
48 NS_DECL_NSIASYNCINPUTSTREAM |
|
49 |
|
50 nsSocketInputStream(nsSocketTransport *); |
|
51 virtual ~nsSocketInputStream(); |
|
52 |
|
53 bool IsReferenced() { return mReaderRefCnt > 0; } |
|
54 nsresult Condition() { return mCondition; } |
|
55 uint64_t ByteCount() { return mByteCount; } |
|
56 |
|
57 // called by the socket transport on the socket thread... |
|
58 void OnSocketReady(nsresult condition); |
|
59 |
|
60 private: |
|
61 nsSocketTransport *mTransport; |
|
62 mozilla::ThreadSafeAutoRefCnt mReaderRefCnt; |
|
63 |
|
64 // access to these is protected by mTransport->mLock |
|
65 nsresult mCondition; |
|
66 nsCOMPtr<nsIInputStreamCallback> mCallback; |
|
67 uint32_t mCallbackFlags; |
|
68 uint64_t mByteCount; |
|
69 }; |
|
70 |
|
71 //----------------------------------------------------------------------------- |
|
72 |
|
73 class nsSocketOutputStream : public nsIAsyncOutputStream |
|
74 { |
|
75 public: |
|
76 NS_DECL_ISUPPORTS_INHERITED |
|
77 NS_DECL_NSIOUTPUTSTREAM |
|
78 NS_DECL_NSIASYNCOUTPUTSTREAM |
|
79 |
|
80 nsSocketOutputStream(nsSocketTransport *); |
|
81 virtual ~nsSocketOutputStream(); |
|
82 |
|
83 bool IsReferenced() { return mWriterRefCnt > 0; } |
|
84 nsresult Condition() { return mCondition; } |
|
85 uint64_t ByteCount() { return mByteCount; } |
|
86 |
|
87 // called by the socket transport on the socket thread... |
|
88 void OnSocketReady(nsresult condition); |
|
89 |
|
90 private: |
|
91 static NS_METHOD WriteFromSegments(nsIInputStream *, void *, |
|
92 const char *, uint32_t offset, |
|
93 uint32_t count, uint32_t *countRead); |
|
94 |
|
95 nsSocketTransport *mTransport; |
|
96 mozilla::ThreadSafeAutoRefCnt mWriterRefCnt; |
|
97 |
|
98 // access to these is protected by mTransport->mLock |
|
99 nsresult mCondition; |
|
100 nsCOMPtr<nsIOutputStreamCallback> mCallback; |
|
101 uint32_t mCallbackFlags; |
|
102 uint64_t mByteCount; |
|
103 }; |
|
104 |
|
105 //----------------------------------------------------------------------------- |
|
106 |
|
107 class nsSocketTransport : public nsASocketHandler |
|
108 , public nsISocketTransport |
|
109 , public nsIDNSListener |
|
110 , public nsIClassInfo |
|
111 { |
|
112 typedef mozilla::Mutex Mutex; |
|
113 |
|
114 public: |
|
115 NS_DECL_THREADSAFE_ISUPPORTS |
|
116 NS_DECL_NSITRANSPORT |
|
117 NS_DECL_NSISOCKETTRANSPORT |
|
118 NS_DECL_NSIDNSLISTENER |
|
119 NS_DECL_NSICLASSINFO |
|
120 |
|
121 nsSocketTransport(); |
|
122 |
|
123 // this method instructs the socket transport to open a socket of the |
|
124 // given type(s) to the given host or proxy. |
|
125 nsresult Init(const char **socketTypes, uint32_t typeCount, |
|
126 const nsACString &host, uint16_t port, |
|
127 nsIProxyInfo *proxyInfo); |
|
128 |
|
129 // this method instructs the socket transport to use an already connected |
|
130 // socket with the given address. |
|
131 nsresult InitWithConnectedSocket(PRFileDesc *socketFD, |
|
132 const mozilla::net::NetAddr *addr); |
|
133 |
|
134 // This method instructs the socket transport to open a socket |
|
135 // connected to the given Unix domain address. We can only create |
|
136 // unlayered, simple, stream sockets. |
|
137 nsresult InitWithFilename(const char *filename); |
|
138 |
|
139 // nsASocketHandler methods: |
|
140 void OnSocketReady(PRFileDesc *, int16_t outFlags); |
|
141 void OnSocketDetached(PRFileDesc *); |
|
142 void IsLocal(bool *aIsLocal); |
|
143 void OnKeepaliveEnabledPrefChange(bool aEnabled) MOZ_OVERRIDE MOZ_FINAL; |
|
144 |
|
145 // called when a socket event is handled |
|
146 void OnSocketEvent(uint32_t type, nsresult status, nsISupports *param); |
|
147 |
|
148 uint64_t ByteCountReceived() { return mInput.ByteCount(); } |
|
149 uint64_t ByteCountSent() { return mOutput.ByteCount(); } |
|
150 protected: |
|
151 |
|
152 virtual ~nsSocketTransport(); |
|
153 |
|
154 private: |
|
155 |
|
156 // event types |
|
157 enum { |
|
158 MSG_ENSURE_CONNECT, |
|
159 MSG_DNS_LOOKUP_COMPLETE, |
|
160 MSG_RETRY_INIT_SOCKET, |
|
161 MSG_TIMEOUT_CHANGED, |
|
162 MSG_INPUT_CLOSED, |
|
163 MSG_INPUT_PENDING, |
|
164 MSG_OUTPUT_CLOSED, |
|
165 MSG_OUTPUT_PENDING |
|
166 }; |
|
167 nsresult PostEvent(uint32_t type, nsresult status = NS_OK, nsISupports *param = nullptr); |
|
168 |
|
169 enum { |
|
170 STATE_CLOSED, |
|
171 STATE_IDLE, |
|
172 STATE_RESOLVING, |
|
173 STATE_CONNECTING, |
|
174 STATE_TRANSFERRING, |
|
175 STATE_SENDINGGET, |
|
176 STATE_SENTGET |
|
177 }; |
|
178 |
|
179 // Safer way to get and automatically release PRFileDesc objects. |
|
180 class MOZ_STACK_CLASS PRFileDescAutoLock |
|
181 { |
|
182 public: |
|
183 typedef mozilla::MutexAutoLock MutexAutoLock; |
|
184 |
|
185 PRFileDescAutoLock(nsSocketTransport *aSocketTransport, |
|
186 nsresult *aConditionWhileLocked = nullptr) |
|
187 : mSocketTransport(aSocketTransport) |
|
188 , mFd(nullptr) |
|
189 { |
|
190 MOZ_ASSERT(aSocketTransport); |
|
191 MutexAutoLock lock(mSocketTransport->mLock); |
|
192 if (aConditionWhileLocked) { |
|
193 *aConditionWhileLocked = mSocketTransport->mCondition; |
|
194 if (NS_FAILED(mSocketTransport->mCondition)) { |
|
195 return; |
|
196 } |
|
197 } |
|
198 mFd = mSocketTransport->GetFD_Locked(); |
|
199 } |
|
200 ~PRFileDescAutoLock() { |
|
201 MutexAutoLock lock(mSocketTransport->mLock); |
|
202 if (mFd) { |
|
203 mSocketTransport->ReleaseFD_Locked(mFd); |
|
204 } |
|
205 } |
|
206 bool IsInitialized() { |
|
207 return mFd; |
|
208 } |
|
209 operator PRFileDesc*() { |
|
210 return mFd; |
|
211 } |
|
212 nsresult SetKeepaliveEnabled(bool aEnable); |
|
213 nsresult SetKeepaliveVals(bool aEnabled, int aIdleTime, |
|
214 int aRetryInterval, int aProbeCount); |
|
215 private: |
|
216 operator PRFileDescAutoLock*() { return nullptr; } |
|
217 |
|
218 // Weak ptr to nsSocketTransport since this is a stack class only. |
|
219 nsSocketTransport *mSocketTransport; |
|
220 PRFileDesc *mFd; |
|
221 }; |
|
222 friend class PRFileDescAutoLock; |
|
223 |
|
224 class LockedPRFileDesc |
|
225 { |
|
226 public: |
|
227 LockedPRFileDesc(nsSocketTransport *aSocketTransport) |
|
228 : mSocketTransport(aSocketTransport) |
|
229 , mFd(nullptr) |
|
230 { |
|
231 MOZ_ASSERT(aSocketTransport); |
|
232 } |
|
233 ~LockedPRFileDesc() {} |
|
234 bool IsInitialized() { |
|
235 return mFd; |
|
236 } |
|
237 LockedPRFileDesc& operator=(PRFileDesc *aFd) { |
|
238 mSocketTransport->mLock.AssertCurrentThreadOwns(); |
|
239 mFd = aFd; |
|
240 return *this; |
|
241 } |
|
242 operator PRFileDesc*() { |
|
243 if (mSocketTransport->mAttached) { |
|
244 mSocketTransport->mLock.AssertCurrentThreadOwns(); |
|
245 } |
|
246 return mFd; |
|
247 } |
|
248 bool operator==(PRFileDesc *aFd) { |
|
249 mSocketTransport->mLock.AssertCurrentThreadOwns(); |
|
250 return mFd == aFd; |
|
251 } |
|
252 private: |
|
253 operator LockedPRFileDesc*() { return nullptr; } |
|
254 // Weak ptr to nsSocketTransport since it owns this class. |
|
255 nsSocketTransport *mSocketTransport; |
|
256 PRFileDesc *mFd; |
|
257 }; |
|
258 friend class LockedPRFileDesc; |
|
259 |
|
260 //------------------------------------------------------------------------- |
|
261 // these members are "set" at initialization time and are never modified |
|
262 // afterwards. this allows them to be safely accessed from any thread. |
|
263 //------------------------------------------------------------------------- |
|
264 |
|
265 // socket type info: |
|
266 char **mTypes; |
|
267 uint32_t mTypeCount; |
|
268 nsCString mHost; |
|
269 uint16_t mPort; |
|
270 bool mHttpsProxy; |
|
271 |
|
272 nsCOMPtr<nsIProxyInfo> mProxyInfo; |
|
273 bool mProxyUse; |
|
274 bool mProxyTransparent; |
|
275 bool mProxyTransparentResolvesHost; |
|
276 uint32_t mConnectionFlags; |
|
277 |
|
278 uint16_t SocketPort(); |
|
279 const nsCString &SocketHost(); |
|
280 nsCString mProxyHostCache; // for SocketHost() only |
|
281 |
|
282 //------------------------------------------------------------------------- |
|
283 // members accessible only on the socket transport thread: |
|
284 // (the exception being initialization/shutdown time) |
|
285 //------------------------------------------------------------------------- |
|
286 |
|
287 // socket state vars: |
|
288 uint32_t mState; // STATE_??? flags |
|
289 bool mAttached; |
|
290 bool mInputClosed; |
|
291 bool mOutputClosed; |
|
292 |
|
293 // this flag is used to determine if the results of a host lookup arrive |
|
294 // recursively or not. this flag is not protected by any lock. |
|
295 bool mResolving; |
|
296 |
|
297 nsCOMPtr<nsICancelable> mDNSRequest; |
|
298 nsCOMPtr<nsIDNSRecord> mDNSRecord; |
|
299 |
|
300 // mNetAddr is valid from GetPeerAddr() once we have |
|
301 // reached STATE_TRANSFERRING. It must not change after that. |
|
302 mozilla::net::NetAddr mNetAddr; |
|
303 bool mNetAddrIsSet; |
|
304 |
|
305 // socket methods (these can only be called on the socket thread): |
|
306 |
|
307 void SendStatus(nsresult status); |
|
308 nsresult ResolveHost(); |
|
309 nsresult BuildSocket(PRFileDesc *&, bool &, bool &); |
|
310 nsresult InitiateSocket(); |
|
311 bool RecoverFromError(); |
|
312 |
|
313 void OnMsgInputPending() |
|
314 { |
|
315 if (mState == STATE_TRANSFERRING) |
|
316 mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT); |
|
317 } |
|
318 void OnMsgOutputPending() |
|
319 { |
|
320 if (mState == STATE_TRANSFERRING) |
|
321 mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT); |
|
322 } |
|
323 void OnMsgInputClosed(nsresult reason); |
|
324 void OnMsgOutputClosed(nsresult reason); |
|
325 |
|
326 // called when the socket is connected |
|
327 void OnSocketConnected(); |
|
328 |
|
329 //------------------------------------------------------------------------- |
|
330 // socket input/output objects. these may be accessed on any thread with |
|
331 // the exception of some specific methods (XXX). |
|
332 |
|
333 Mutex mLock; // protects members in this section. |
|
334 LockedPRFileDesc mFD; |
|
335 nsrefcnt mFDref; // mFD is closed when mFDref goes to zero. |
|
336 bool mFDconnected; // mFD is available to consumer when TRUE. |
|
337 |
|
338 // A delete protector reference to gSocketTransportService held for lifetime |
|
339 // of 'this'. Sometimes used interchangably with gSocketTransportService due |
|
340 // to scoping. |
|
341 nsRefPtr<nsSocketTransportService> mSocketTransportService; |
|
342 |
|
343 nsCOMPtr<nsIInterfaceRequestor> mCallbacks; |
|
344 nsCOMPtr<nsITransportEventSink> mEventSink; |
|
345 nsCOMPtr<nsISupports> mSecInfo; |
|
346 |
|
347 nsSocketInputStream mInput; |
|
348 nsSocketOutputStream mOutput; |
|
349 |
|
350 friend class nsSocketInputStream; |
|
351 friend class nsSocketOutputStream; |
|
352 |
|
353 // socket timeouts are not protected by any lock. |
|
354 uint16_t mTimeouts[2]; |
|
355 |
|
356 // QoS setting for socket |
|
357 uint8_t mQoSBits; |
|
358 |
|
359 // |
|
360 // mFD access methods: called with mLock held. |
|
361 // |
|
362 PRFileDesc *GetFD_Locked(); |
|
363 void ReleaseFD_Locked(PRFileDesc *fd); |
|
364 |
|
365 // |
|
366 // stream state changes (called outside mLock): |
|
367 // |
|
368 void OnInputClosed(nsresult reason) |
|
369 { |
|
370 // no need to post an event if called on the socket thread |
|
371 if (PR_GetCurrentThread() == gSocketThread) |
|
372 OnMsgInputClosed(reason); |
|
373 else |
|
374 PostEvent(MSG_INPUT_CLOSED, reason); |
|
375 } |
|
376 void OnInputPending() |
|
377 { |
|
378 // no need to post an event if called on the socket thread |
|
379 if (PR_GetCurrentThread() == gSocketThread) |
|
380 OnMsgInputPending(); |
|
381 else |
|
382 PostEvent(MSG_INPUT_PENDING); |
|
383 } |
|
384 void OnOutputClosed(nsresult reason) |
|
385 { |
|
386 // no need to post an event if called on the socket thread |
|
387 if (PR_GetCurrentThread() == gSocketThread) |
|
388 OnMsgOutputClosed(reason); // XXX need to not be inside lock! |
|
389 else |
|
390 PostEvent(MSG_OUTPUT_CLOSED, reason); |
|
391 } |
|
392 void OnOutputPending() |
|
393 { |
|
394 // no need to post an event if called on the socket thread |
|
395 if (PR_GetCurrentThread() == gSocketThread) |
|
396 OnMsgOutputPending(); |
|
397 else |
|
398 PostEvent(MSG_OUTPUT_PENDING); |
|
399 } |
|
400 |
|
401 #ifdef ENABLE_SOCKET_TRACING |
|
402 void TraceInBuf(const char *buf, int32_t n); |
|
403 void TraceOutBuf(const char *buf, int32_t n); |
|
404 #endif |
|
405 |
|
406 // Reads prefs to get default keepalive config. |
|
407 nsresult EnsureKeepaliveValsAreInitialized(); |
|
408 |
|
409 // Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals. |
|
410 nsresult SetKeepaliveEnabledInternal(bool aEnable); |
|
411 |
|
412 // True if keepalive has been enabled by the socket owner. Note: Keepalive |
|
413 // must also be enabled globally for it to be enabled in TCP. |
|
414 bool mKeepaliveEnabled; |
|
415 |
|
416 // Keepalive config (support varies by platform). |
|
417 int32_t mKeepaliveIdleTimeS; |
|
418 int32_t mKeepaliveRetryIntervalS; |
|
419 int32_t mKeepaliveProbeCount; |
|
420 }; |
|
421 |
|
422 #endif // !nsSocketTransport_h__ |