2009-01-19 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mcs / class / System / System.Net.Sockets / TcpListener.cs
1 // System.Net.Sockets.TcpListener.cs
2 //
3 // Authors:
4 //    Phillip Pearson (pp@myelin.co.nz)
5 //    Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //        Patrik Torstensson
7 //    Sridhar Kulkarni (sridharkulkarni@gmail.com)
8 //
9 // Copyright (C) 2001, Phillip Pearson
10 //    http://www.myelin.co.nz
11 //
12 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
13 // (c) 2004-2006 Novell, Inc.
14 //
15
16 //
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
24 // 
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
27 // 
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 //
36
37 using System;
38 using System.Net;
39
40 namespace System.Net.Sockets
41 {
42         /// <remarks>
43         /// A slightly more abstracted way to listen for incoming
44         /// network connections than a Socket.
45         /// </remarks>
46         public class TcpListener
47         {
48                 // private data
49                 
50                 bool active;
51                 Socket server;
52                 EndPoint savedEP;
53                 
54                 // constructor
55
56                 /// <summary>
57                 /// Some code that is shared between the constructors.
58                 /// </summary>
59                 private void Init (AddressFamily family, EndPoint ep)
60                 {
61                         active = false;
62                         server = new Socket(family, SocketType.Stream, ProtocolType.Tcp);
63                         savedEP = ep;
64                 }
65                 
66                 /// <summary>
67                 /// Constructs a new TcpListener to listen on a specified port
68                 /// </summary>
69                 /// <param name="port">The port to listen on, e.g. 80 if you 
70                 /// are a web server</param>
71 #if NET_1_1
72                 [Obsolete ("Use TcpListener (IPAddress address, int port) instead")]
73 #endif
74                 public TcpListener (int port)
75                 {
76                         if (port < 0 || port > 65535)
77                                 throw new ArgumentOutOfRangeException ("port");
78
79                         Init (AddressFamily.InterNetwork, new IPEndPoint (IPAddress.Any, port));
80                 }
81
82                 /// <summary>
83                 /// Constructs a new TcpListener with a specified local endpoint
84                 /// </summary>
85                 /// <param name="local_end_point">The endpoint</param>
86                 public TcpListener (IPEndPoint local_end_point)
87                 {
88                         if (local_end_point == null)
89                                 throw new ArgumentNullException ("local_end_point");
90
91                         Init (local_end_point.AddressFamily, local_end_point);
92                 }
93                 
94                 /// <summary>
95                 /// Constructs a new TcpListener, listening on a specified port
96                 /// and IP (for use on a multi-homed machine)
97                 /// </summary>
98                 /// <param name="listen_ip">The IP to listen on</param>
99                 /// <param name="port">The port to listen on</param>
100                 public TcpListener (IPAddress listen_ip, int port)
101                 {
102                         if (listen_ip == null)
103                                 throw new ArgumentNullException ("listen_ip");
104
105                         if (port < 0 || port > 65535)
106                                 throw new ArgumentOutOfRangeException ("port");
107
108                         Init (listen_ip.AddressFamily, new IPEndPoint(listen_ip, port));
109                 }
110
111
112                 // properties
113
114                 /// <summary>
115                 /// A flag that is 'true' if the TcpListener is listening,
116                 /// or 'false' if it is not listening
117                 /// </summary>
118                 protected bool Active
119                 {
120                         get { return active; }
121                 }
122
123                 /// <summary>
124                 /// The local end point
125                 /// </summary>
126                 public EndPoint LocalEndpoint
127                 {
128                         get { 
129                                 if (active)
130                                         return server.LocalEndPoint;
131
132                                 return savedEP; 
133                         }
134                 }
135                 
136                 /// <summary>
137                 /// The listening socket
138                 /// </summary>
139 #if NET_2_0
140                 public
141 #else
142                 protected
143 #endif
144                 Socket Server
145                 {
146                         get { return server; }
147                 }
148
149 #if NET_2_0
150                 /// <summary>
151                 /// Specifies whether the TcpListener allows only one
152                 /// underlying socket to listen to a specific port
153                 /// </summary>
154 #if TARGET_JVM
155                 [MonoNotSupported ("Not supported as Socket.ExclusiveAddressUse is not supported")]
156 #endif
157                 public bool ExclusiveAddressUse
158                 {
159                         get {
160                                 if (server == null) {
161                                         throw new ObjectDisposedException (GetType ().ToString ());
162                                 }
163                                 if (active) {
164                                         throw new InvalidOperationException ("The TcpListener has been started");
165                                 }
166
167                                 return(server.ExclusiveAddressUse);
168                         }
169                         set {
170                                 if (server == null) {
171                                         throw new ObjectDisposedException (GetType ().ToString ());
172                                 }
173                                 if (active) {
174                                         throw new InvalidOperationException ("The TcpListener has been started");
175                                 }
176
177                                 server.ExclusiveAddressUse = value;
178                         }
179                 }
180 #endif
181                 
182                 // methods
183
184                 /// <summary>
185                 /// Accepts a pending connection
186                 /// </summary>
187                 /// <returns>A Socket object for the new connection</returns>
188                 public Socket AcceptSocket ()
189                 {
190                         if (!active)
191                                 throw new InvalidOperationException ("Socket is not listening");
192
193                         return server.Accept();
194                 }
195                 
196                 /// <summary>
197                 /// Accepts a pending connection
198                 /// </summary>
199                 /// <returns>A TcpClient
200                 /// object made from the new socket.</returns>
201                 public TcpClient AcceptTcpClient ()
202                 {
203                         if (!active)
204                                 throw new InvalidOperationException ("Socket is not listening");
205
206                         Socket clientSocket = server.Accept ();
207
208                         TcpClient client = new TcpClient();
209                         // use internal method SetTcpClient to make a
210                         // client with the specified socket
211                         client.SetTcpClient (clientSocket);
212                         
213                         return client;
214                 }
215                 
216                 /// <summary>
217                 /// Destructor - stops the listener listening
218                 /// </summary>
219                 ~TcpListener ()
220                 {
221                         if (active)
222                                 Stop();
223                 }
224         
225                 /// <returns>
226                 /// Returns 'true' if there is a connection waiting to be accepted
227                 /// with AcceptSocket() or AcceptTcpClient().
228                 /// </returns>
229                 public bool Pending ()
230                 {
231                         if (!active)
232                                 throw new InvalidOperationException ("Socket is not listening");
233
234                         return server.Poll(0, SelectMode.SelectRead);
235                 }
236                 
237                 /// <summary>
238                 /// Tells the TcpListener to start listening.
239                 /// </summary>
240                 public void Start ()
241                 {
242                         // MS: sets Listen to Int32.MaxValue
243                         this.Start (5);
244                         // According to the man page some BSD and BSD-derived
245                         // systems limit the backlog to 5.  This should really be
246                         // configurable though
247                 }
248
249                 /// <summary>
250                 /// Tells the TcpListener to start listening for max number
251                 /// of pending connections.
252                 /// </summary>
253
254 #if NET_2_0
255                 public
256 #else
257                 private
258 #endif
259                 void Start (int backlog)
260                 {
261                         if (active) {
262                                 return;
263                         }
264                         if (server == null) {
265                                 throw new InvalidOperationException ("Invalid server socket");
266                         }
267                         
268                         server.Bind (savedEP);
269                         server.Listen (backlog);
270                         active = true;
271                 }
272
273 #if NET_2_0             
274                 public IAsyncResult BeginAcceptSocket (AsyncCallback callback,
275                                                        object state)
276                 {
277                         if (server == null) {
278                                 throw new ObjectDisposedException (GetType ().ToString ());
279                         }
280                         
281                         return(server.BeginAccept (callback, state));
282                 }
283                 
284                 public IAsyncResult BeginAcceptTcpClient (AsyncCallback callback, object state)
285                 {
286                         if (server == null) {
287                                 throw new ObjectDisposedException (GetType ().ToString ());
288                         }
289                         
290                         return(server.BeginAccept (callback, state));
291                 }
292                 
293                 public Socket EndAcceptSocket (IAsyncResult asyncResult) 
294                 {
295                         return(server.EndAccept (asyncResult));
296                 }
297                 
298                 public TcpClient EndAcceptTcpClient (IAsyncResult asyncResult)
299                 {
300                         Socket clientSocket = server.EndAccept (asyncResult);
301                         TcpClient client = new TcpClient ();
302                         
303                         client.SetTcpClient (clientSocket);
304                         
305                         return(client);
306                 }
307 #endif
308                 
309                 /// <summary>
310                 /// Tells the TcpListener to stop listening and dispose
311                 /// of all managed resources.
312                 /// </summary>
313                 public void Stop ()
314                 {
315                         if (active) 
316                         {
317                                 server.Close ();
318                                 server = null;
319                         }
320
321                         Init (AddressFamily.InterNetwork, savedEP);
322                 }
323
324         }
325 }