213f0b72d3fd1d4dca44d580f64ce9ce0bb05b1e
[mono.git] / mcs / class / System / Test / System.Net / SocketResponder.cs
1 //
2 // SocketResponder.cs - Utility class for tests that require a listener
3 //
4 // Author:
5 //      Gert Driesen (drieseng@users.sourceforge.net)
6 //
7 // Copyright (C) 2007 Gert Driesen
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.Globalization;
31 using System.IO;
32 using System.Net;
33 using System.Net.Sockets;
34 using System.Text;
35 using System.Threading;
36
37 namespace MonoTests.System.Net
38 {
39         public delegate byte [] SocketRequestHandler (Socket socket);
40
41         public class SocketResponder : IDisposable
42         {
43                 private TcpListener tcpListener;
44                 private readonly IPEndPoint _localEndPoint;
45                 private Thread listenThread;
46                 private Socket listenSocket;
47                 private SocketRequestHandler _requestHandler;
48                 private int _state = 0;
49                 private readonly object _syncRoot = new object ();
50
51                 private const int SOCKET_CLOSED = 10004;
52                 private const int SOCKET_INVALID_ARGS = 10022;
53
54                 private const int STATE_UNINITIALIZED = 0;
55                 private const int STATE_RUNNING = 1;
56                 private const int STATE_STOPPED = 2;
57
58                 public SocketResponder (IPEndPoint localEP, SocketRequestHandler requestHandler)
59                 {
60                         _localEndPoint = localEP;
61                         _requestHandler = requestHandler;
62                 }
63
64                 public IPEndPoint LocalEndPoint
65                 {
66                         get { return _localEndPoint; }
67                 }
68
69                 public void Dispose ()
70                 {
71                         Stop ();
72                 }
73
74                 public bool IsStopped
75                 {
76                         get
77                         {
78                                 lock (_syncRoot) {
79                                         return _state != STATE_RUNNING;
80                                 }
81                         }
82                 }
83
84                 public void Start ()
85                 {
86                         lock (_syncRoot) {
87                                 if (_state != STATE_UNINITIALIZED)
88                                         throw new InvalidOperationException ("cannot restart SocketResponder");
89                                 _state = STATE_RUNNING;
90                                 tcpListener = new TcpListener (LocalEndPoint);
91                                 tcpListener.Start ();
92                                 listenThread = new Thread (new ThreadStart (Listen));
93                                 listenThread.Start ();
94                         }
95                 }
96
97                 public void Stop ()
98                 {
99                         lock (_syncRoot) {
100                                 if (_state != STATE_RUNNING)
101                                         return;
102                                 _state = STATE_STOPPED;
103                                 if (tcpListener != null) {
104                                         tcpListener.Stop ();
105                                         tcpListener = null;
106                                         if (listenSocket != null)
107                                                 listenSocket.Close ();
108 #if MONO_FEATURE_THREAD_ABORT
109                                         listenThread.Abort ();
110 #else
111                                         listenThread.Interrupt ();
112 #endif
113                                         listenThread.Join ();
114                                         listenThread = null;
115                                         Thread.Sleep (50);
116                                 }
117                         }
118                 }
119
120                 private void Listen ()
121                 {
122                         while (_state == STATE_RUNNING) {
123                                 listenSocket = null;
124                                 try {
125                                         listenSocket = tcpListener.AcceptSocket ();
126                                         listenSocket.Send (_requestHandler (listenSocket));
127                                         try {
128                                                 listenSocket.Shutdown (SocketShutdown.Receive);
129                                                 listenSocket.Shutdown (SocketShutdown.Send);
130                                         } catch {
131                                         }
132                                 } catch (SocketException ex) {
133                                         // ignore interruption of blocking call
134                                         if (ex.ErrorCode != SOCKET_CLOSED && ex.ErrorCode != SOCKET_INVALID_ARGS && _state != STATE_STOPPED)
135                                                 throw;
136                                 } catch (ObjectDisposedException ex) {
137                                         Console.WriteLine (ex);
138                                         if (_state != STATE_STOPPED)
139                                                 throw;
140 #if MOBILE
141                                 } catch (InvalidOperationException ex) {
142                                         // This breaks some tests running on Android. The problem is that the stack trace
143                                         // doesn't point to where the exception is actually thrown from but the entire process
144                                         // is aborted because of unhandled exception.
145                                         Console.WriteLine ("SocketResponder.Listen failed:");
146                                         Console.WriteLine (ex);
147 #endif
148                                 } finally {
149                                         Thread.Sleep (500);
150                                         if (listenSocket != null)
151                                                 listenSocket.Close ();
152                                 }
153                         }
154                 }
155         }
156 }