[Microsoft.Build] Fix expected output newline from ProcessWrapper.OutputStreamChanged...
[mono.git] / mcs / class / test-helpers / 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.Tasks;
36
37 namespace MonoTests.Helpers
38 {
39         public delegate byte [] SocketRequestHandler (Socket socket);
40
41         public class SocketResponderException : Exception
42         {
43                 public SocketResponderException (string message)
44                         : base (message)
45                 {
46                 }
47         }
48
49         public class SocketResponder : IDisposable
50         {
51                 private TcpListener tcpListener;
52                 private Task listenTask;
53                 private Socket listenSocket;
54                 private SocketRequestHandler requestHandler;
55                 private bool disposed;
56
57                 private const int SOCKET_CLOSED = 10004;
58                 private const int SOCKET_INVALID_ARGS = 10022;
59
60                 public SocketResponder (IPEndPoint ep, SocketRequestHandler rh)
61                 {
62                         requestHandler = rh;
63
64                         tcpListener = new TcpListener (ep);
65                         tcpListener.Start ();
66
67                         listenTask = Task.Run (Listen);
68                 }
69
70                 public void Dispose ()
71                 {
72                         if (disposed)
73                                 return;
74
75                         disposed = true;
76
77                         tcpListener.Stop ();
78
79                         if (listenSocket != null)
80                                 listenSocket.Close ();
81
82                         if (!listenTask.Wait (5000))
83                                 throw new SocketResponderException ("Failed to stop in less than 5 seconds");
84                 }
85
86                 private void Listen ()
87                 {
88                         while (!disposed) {
89                                 listenSocket = null;
90                                 try {
91                                         listenSocket = tcpListener.AcceptSocket ();
92                                         listenSocket.Send (requestHandler (listenSocket));
93                                         try {
94                                                 listenSocket.Shutdown (SocketShutdown.Receive);
95                                                 listenSocket.Shutdown (SocketShutdown.Send);
96                                         } catch {
97                                         }
98                                 } catch (SocketException ex) {
99                                         // ignore interruption of blocking call
100                                         if (ex.ErrorCode != SOCKET_CLOSED && ex.ErrorCode != SOCKET_INVALID_ARGS && !disposed)
101                                                 throw;
102                                 } catch (ObjectDisposedException ex) {
103                                         if (!disposed)
104                                                 throw;
105 #if MOBILE
106                                 } catch (InvalidOperationException ex) {
107                                         // This breaks some tests running on Android. The problem is that the stack trace
108                                         // doesn't point to where the exception is actually thrown from but the entire process
109                                         // is aborted because of unhandled exception.
110                                         Console.WriteLine ("SocketResponder.Listen failed:");
111                                         Console.WriteLine (ex);
112 #endif
113                                 } finally {
114                                         if (listenSocket != null)
115                                                 listenSocket.Close ();
116                                 }
117                         }
118                 }
119         }
120 }