1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Mozilla.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Netscape Communications Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2002
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Darin Fisher <darin@netscape.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef nsSocketTransport2_h__
39 : #define nsSocketTransport2_h__
40 :
41 : #ifdef DEBUG_darinf
42 : #define ENABLE_SOCKET_TRACING
43 : #endif
44 :
45 : #include "mozilla/Mutex.h"
46 : #include "nsSocketTransportService2.h"
47 : #include "nsString.h"
48 : #include "nsCOMPtr.h"
49 :
50 : #include "nsISocketTransport.h"
51 : #include "nsIInterfaceRequestor.h"
52 : #include "nsIAsyncInputStream.h"
53 : #include "nsIAsyncOutputStream.h"
54 : #include "nsIDNSListener.h"
55 : #include "nsIDNSRecord.h"
56 : #include "nsICancelable.h"
57 : #include "nsIClassInfo.h"
58 :
59 : class nsSocketTransport;
60 :
61 : //-----------------------------------------------------------------------------
62 :
63 : // after this short interval, we will return to PR_Poll
64 : #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20)
65 :
66 : //-----------------------------------------------------------------------------
67 :
68 : class nsSocketInputStream : public nsIAsyncInputStream
69 : {
70 : public:
71 : NS_DECL_ISUPPORTS_INHERITED
72 : NS_DECL_NSIINPUTSTREAM
73 : NS_DECL_NSIASYNCINPUTSTREAM
74 :
75 : nsSocketInputStream(nsSocketTransport *);
76 : virtual ~nsSocketInputStream();
77 :
78 5882 : bool IsReferenced() { return mReaderRefCnt > 0; }
79 : nsresult Condition() { return mCondition; }
80 9349 : PRUint64 ByteCount() { return mByteCount; }
81 :
82 : // called by the socket transport on the socket thread...
83 : void OnSocketReady(nsresult condition);
84 :
85 : private:
86 : nsSocketTransport *mTransport;
87 : nsrefcnt mReaderRefCnt;
88 :
89 : // access to these is protected by mTransport->mLock
90 : nsresult mCondition;
91 : nsCOMPtr<nsIInputStreamCallback> mCallback;
92 : PRUint32 mCallbackFlags;
93 : PRUint64 mByteCount;
94 : };
95 :
96 : //-----------------------------------------------------------------------------
97 :
98 : class nsSocketOutputStream : public nsIAsyncOutputStream
99 : {
100 : public:
101 : NS_DECL_ISUPPORTS_INHERITED
102 : NS_DECL_NSIOUTPUTSTREAM
103 : NS_DECL_NSIASYNCOUTPUTSTREAM
104 :
105 : nsSocketOutputStream(nsSocketTransport *);
106 : virtual ~nsSocketOutputStream();
107 :
108 5883 : bool IsReferenced() { return mWriterRefCnt > 0; }
109 : nsresult Condition() { return mCondition; }
110 9344 : PRUint64 ByteCount() { return mByteCount; }
111 :
112 : // called by the socket transport on the socket thread...
113 : void OnSocketReady(nsresult condition);
114 :
115 : private:
116 : static NS_METHOD WriteFromSegments(nsIInputStream *, void *,
117 : const char *, PRUint32 offset,
118 : PRUint32 count, PRUint32 *countRead);
119 :
120 : nsSocketTransport *mTransport;
121 : nsrefcnt mWriterRefCnt;
122 :
123 : // access to these is protected by mTransport->mLock
124 : nsresult mCondition;
125 : nsCOMPtr<nsIOutputStreamCallback> mCallback;
126 : PRUint32 mCallbackFlags;
127 : PRUint64 mByteCount;
128 : };
129 :
130 : //-----------------------------------------------------------------------------
131 :
132 : class nsSocketTransport : public nsASocketHandler
133 : , public nsISocketTransport
134 : , public nsIDNSListener
135 : , public nsIClassInfo
136 : {
137 : typedef mozilla::Mutex Mutex;
138 :
139 : public:
140 : NS_DECL_ISUPPORTS
141 : NS_DECL_NSITRANSPORT
142 : NS_DECL_NSISOCKETTRANSPORT
143 : NS_DECL_NSIDNSLISTENER
144 : NS_DECL_NSICLASSINFO
145 :
146 : nsSocketTransport();
147 :
148 : // this method instructs the socket transport to open a socket of the
149 : // given type(s) to the given host or proxy.
150 : nsresult Init(const char **socketTypes, PRUint32 typeCount,
151 : const nsACString &host, PRUint16 port,
152 : nsIProxyInfo *proxyInfo);
153 :
154 : // this method instructs the socket transport to use an already connected
155 : // socket with the given address.
156 : nsresult InitWithConnectedSocket(PRFileDesc *socketFD,
157 : const PRNetAddr *addr);
158 :
159 : // nsASocketHandler methods:
160 : void OnSocketReady(PRFileDesc *, PRInt16 outFlags);
161 : void OnSocketDetached(PRFileDesc *);
162 :
163 : // called when a socket event is handled
164 : void OnSocketEvent(PRUint32 type, nsresult status, nsISupports *param);
165 :
166 : protected:
167 :
168 : virtual ~nsSocketTransport();
169 :
170 : private:
171 :
172 : // event types
173 : enum {
174 : MSG_ENSURE_CONNECT,
175 : MSG_DNS_LOOKUP_COMPLETE,
176 : MSG_RETRY_INIT_SOCKET,
177 : MSG_TIMEOUT_CHANGED,
178 : MSG_INPUT_CLOSED,
179 : MSG_INPUT_PENDING,
180 : MSG_OUTPUT_CLOSED,
181 : MSG_OUTPUT_PENDING
182 : };
183 : nsresult PostEvent(PRUint32 type, nsresult status = NS_OK, nsISupports *param = nsnull);
184 :
185 : enum {
186 : STATE_CLOSED,
187 : STATE_IDLE,
188 : STATE_RESOLVING,
189 : STATE_CONNECTING,
190 : STATE_TRANSFERRING
191 : };
192 :
193 : //-------------------------------------------------------------------------
194 : // these members are "set" at initialization time and are never modified
195 : // afterwards. this allows them to be safely accessed from any thread.
196 : //-------------------------------------------------------------------------
197 :
198 : // socket type info:
199 : char **mTypes;
200 : PRUint32 mTypeCount;
201 : nsCString mHost;
202 : nsCString mProxyHost;
203 : PRUint16 mPort;
204 : PRUint16 mProxyPort;
205 : bool mProxyTransparent;
206 : bool mProxyTransparentResolvesHost;
207 : PRUint32 mConnectionFlags;
208 :
209 9008 : PRUint16 SocketPort() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; }
210 5878 : const nsCString &SocketHost() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyHost : mHost; }
211 :
212 : //-------------------------------------------------------------------------
213 : // members accessible only on the socket transport thread:
214 : // (the exception being initialization/shutdown time)
215 : //-------------------------------------------------------------------------
216 :
217 : // socket state vars:
218 : PRUint32 mState; // STATE_??? flags
219 : bool mAttached;
220 : bool mInputClosed;
221 : bool mOutputClosed;
222 :
223 : // this flag is used to determine if the results of a host lookup arrive
224 : // recursively or not. this flag is not protected by any lock.
225 : bool mResolving;
226 :
227 : nsCOMPtr<nsICancelable> mDNSRequest;
228 : nsCOMPtr<nsIDNSRecord> mDNSRecord;
229 :
230 : // mNetAddr is valid from GetPeerAddr() once we have
231 : // reached STATE_TRANSFERRING. It must not change after that.
232 : PRNetAddr mNetAddr;
233 : bool mNetAddrIsSet;
234 :
235 : // socket methods (these can only be called on the socket thread):
236 :
237 : void SendStatus(nsresult status);
238 : nsresult ResolveHost();
239 : nsresult BuildSocket(PRFileDesc *&, bool &, bool &);
240 : nsresult InitiateSocket();
241 : bool RecoverFromError();
242 :
243 9253 : void OnMsgInputPending()
244 : {
245 9253 : if (mState == STATE_TRANSFERRING)
246 9217 : mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT);
247 9253 : }
248 12235 : void OnMsgOutputPending()
249 : {
250 12235 : if (mState == STATE_TRANSFERRING)
251 9246 : mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT);
252 12235 : }
253 : void OnMsgInputClosed(nsresult reason);
254 : void OnMsgOutputClosed(nsresult reason);
255 :
256 : // called when the socket is connected
257 : void OnSocketConnected();
258 :
259 : //-------------------------------------------------------------------------
260 : // socket input/output objects. these may be accessed on any thread with
261 : // the exception of some specific methods (XXX).
262 :
263 : Mutex mLock; // protects members in this section
264 : PRFileDesc *mFD;
265 : nsrefcnt mFDref; // mFD is closed when mFDref goes to zero.
266 : bool mFDconnected; // mFD is available to consumer when TRUE.
267 :
268 : nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
269 : nsCOMPtr<nsITransportEventSink> mEventSink;
270 : nsCOMPtr<nsISupports> mSecInfo;
271 :
272 : nsSocketInputStream mInput;
273 : nsSocketOutputStream mOutput;
274 :
275 : friend class nsSocketInputStream;
276 : friend class nsSocketOutputStream;
277 :
278 : // socket timeouts are not protected by any lock.
279 : PRUint16 mTimeouts[2];
280 :
281 : // QoS setting for socket
282 : PRUint8 mQoSBits;
283 :
284 : //
285 : // mFD access methods: called with mLock held.
286 : //
287 : PRFileDesc *GetFD_Locked();
288 : void ReleaseFD_Locked(PRFileDesc *fd);
289 :
290 : //
291 : // stream state changes (called outside mLock):
292 : //
293 5739 : void OnInputClosed(nsresult reason)
294 : {
295 : // no need to post an event if called on the socket thread
296 5739 : if (PR_GetCurrentThread() == gSocketThread)
297 5739 : OnMsgInputClosed(reason);
298 : else
299 0 : PostEvent(MSG_INPUT_CLOSED, reason);
300 5739 : }
301 9253 : void OnInputPending()
302 : {
303 : // no need to post an event if called on the socket thread
304 9253 : if (PR_GetCurrentThread() == gSocketThread)
305 9253 : OnMsgInputPending();
306 : else
307 0 : PostEvent(MSG_INPUT_PENDING);
308 9253 : }
309 5736 : void OnOutputClosed(nsresult reason)
310 : {
311 : // no need to post an event if called on the socket thread
312 5736 : if (PR_GetCurrentThread() == gSocketThread)
313 5736 : OnMsgOutputClosed(reason); // XXX need to not be inside lock!
314 : else
315 0 : PostEvent(MSG_OUTPUT_CLOSED, reason);
316 5736 : }
317 12235 : void OnOutputPending()
318 : {
319 : // no need to post an event if called on the socket thread
320 12235 : if (PR_GetCurrentThread() == gSocketThread)
321 12235 : OnMsgOutputPending();
322 : else
323 0 : PostEvent(MSG_OUTPUT_PENDING);
324 12235 : }
325 :
326 : #ifdef ENABLE_SOCKET_TRACING
327 : void TraceInBuf(const char *buf, PRInt32 n);
328 : void TraceOutBuf(const char *buf, PRInt32 n);
329 : #endif
330 : };
331 :
332 : #endif // !nsSocketTransport_h__
|