[sgen] Untag the vtable during concurrent mark
[mono.git] / mcs / class / System / ReferenceSources / _SslStream.cs
1 //
2 // Mono-specific additions to Microsoft's _SslStream.cs
3 //
4 #if MONO_FEATURE_NEW_TLS && SECURITY_DEP
5 namespace System.Net.Security
6 {
7         using System.IO;
8         using System.Threading;
9         using System.Net.Sockets;
10
11         partial class _SslStream
12         {
13                 static readonly AsyncCallback _HandshakeWriteCallback = new AsyncCallback (HandshakeWriteCallback);
14                 static readonly HandshakeProtocolCallback _ResumeHandshakeWriteCallback = new HandshakeProtocolCallback (ResumeHandshakeWriteCallback);
15
16                 internal void BeginShutdown (LazyAsyncResult lazyResult)
17                 {
18                         HandshakeProtocolRequest asyncRequest = new HandshakeProtocolRequest (lazyResult);
19
20                         if (Interlocked.Exchange (ref _NestedWrite, 1) == 1)
21                                 throw new NotSupportedException (SR.GetString (SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginShutdown" : "Shutdown"), "shutdown"));
22
23                         bool failed = false;
24                         try
25                         {
26                                 ProtocolToken message = _SslState.CreateShutdownMessage ();
27                                 asyncRequest.SetNextRequest (HandshakeProtocolState.Shutdown, message, _ResumeHandshakeWriteCallback);
28
29                                 StartHandshakeWrite (asyncRequest);
30                         } catch (Exception e) {
31                                 _SslState.FinishWrite ();
32                                 failed = true;
33                                 throw;
34                         } finally {
35                                 if (failed)
36                                         _NestedWrite = 0;
37                         }
38                 }
39
40                 internal void EndShutdown (LazyAsyncResult lazyResult)
41                 {
42                         if (Interlocked.Exchange (ref _NestedWrite, 0) == 0)
43                                 throw new InvalidOperationException (SR.GetString (SR.net_io_invalidendcall, "EndShutdown"));
44
45                         // No "artificial" timeouts implemented so far, InnerStream controls timeout.
46                         lazyResult.InternalWaitForCompletion ();
47
48                         if (lazyResult.Result is Exception) {
49                                 if (lazyResult.Result is IOException)
50                                         throw (Exception)lazyResult.Result;
51                                 throw new IOException (SR.GetString (SR.mono_net_io_shutdown), (Exception)lazyResult.Result);
52                         }
53                 }
54
55                 internal void BeginRenegotiate (LazyAsyncResult lazyResult)
56                 {
57                         HandshakeProtocolRequest asyncRequest = new HandshakeProtocolRequest (lazyResult);
58
59                         if (Interlocked.Exchange (ref _NestedWrite, 1) == 1)
60                                 throw new NotSupportedException (SR.GetString (SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginRenegotiate" : "Renegotiate"), "renegotiate"));
61
62                         bool failed = false;
63                         try
64                         {
65                                 if (_SslState.IsServer) {
66                                         ProtocolToken message = _SslState.CreateHelloRequestMessage ();
67                                         asyncRequest.SetNextRequest (HandshakeProtocolState.SendHelloRequest, message, _ResumeHandshakeWriteCallback);
68                                 } else {
69                                         asyncRequest.SetNextRequest (HandshakeProtocolState.ClientRenegotiation, null, _ResumeHandshakeWriteCallback);
70                                 }
71
72                                 StartHandshakeWrite (asyncRequest);
73                         } catch (Exception e) {
74                                 _SslState.FinishWrite ();
75                                 failed = true;
76                                 throw;
77                         } finally {
78                                 if (failed)
79                                         _NestedWrite = 0;
80                         }
81                 }
82
83                 internal void EndRenegotiate (LazyAsyncResult lazyResult)
84                 {
85                         if (Interlocked.Exchange (ref _NestedWrite, 0) == 0)
86                                 throw new InvalidOperationException (SR.GetString (SR.net_io_invalidendcall, "EndRenegotiate"));
87
88                         // No "artificial" timeouts implemented so far, InnerStream controls timeout.
89                         lazyResult.InternalWaitForCompletion();
90
91                         if (lazyResult.Result is Exception) {
92                                 if (lazyResult.Result is IOException)
93                                         throw (Exception)lazyResult.Result;
94                                 throw new IOException (SR.GetString (SR.mono_net_io_renegotiate), (Exception)lazyResult.Result);
95                         }
96                 }
97
98                 void StartHandshakeWrite (HandshakeProtocolRequest asyncRequest)
99                 {
100                         byte[] buffer = null;
101                         if (asyncRequest.Message != null) {
102                                 buffer = asyncRequest.Message.Payload;
103                                 if (buffer.Length != asyncRequest.Message.Size) {
104                                         buffer = new byte [asyncRequest.Message.Size];
105                                         Buffer.BlockCopy (asyncRequest.Message.Payload, 0, buffer, 0, buffer.Length);
106                                 }
107                         }
108
109                         switch (asyncRequest.State) {
110                         case HandshakeProtocolState.ClientRenegotiation:
111                         case HandshakeProtocolState.ServerRenegotiation:
112                                 _SslState.StartReHandshake (asyncRequest);
113                                 return;
114
115                         case HandshakeProtocolState.SendHelloRequest:
116                                 if (_SslState.CheckEnqueueHandshakeWrite (buffer, asyncRequest)) {
117                                         // operation is async and has been queued, return.
118                                         return;
119                                 }
120                                 break;
121
122                         case HandshakeProtocolState.Shutdown:
123                                 if (_SslState.CheckEnqueueWrite (asyncRequest)) {
124                                         // operation is async and has been queued, return.
125                                         return;
126                                 }
127                                 break;
128
129                         default:
130                                 throw new InvalidOperationException ();
131                         }
132
133                         if (_SslState.LastPayload != null)
134                                 throw new InvalidOperationException ();
135
136                         // prepare for the next request
137                         IAsyncResult ar = ((NetworkStream)_SslState.InnerStream).BeginWrite (buffer, 0, buffer.Length, _HandshakeWriteCallback, asyncRequest);
138                         if (!ar.CompletedSynchronously)
139                                 return;
140
141                         HandshakeWriteCallback (asyncRequest, ar);
142                 }
143
144                 static void HandshakeWriteCallback (IAsyncResult transportResult)
145                 {
146                         if (transportResult.CompletedSynchronously)
147                                 return;
148
149                         HandshakeProtocolRequest asyncRequest = (HandshakeProtocolRequest)transportResult.AsyncState;
150
151                         SslState sslState = (SslState)asyncRequest.AsyncObject;
152                         sslState.SecureStream.HandshakeWriteCallback (asyncRequest, transportResult);
153                 }
154
155                 void HandshakeWriteCallback (HandshakeProtocolRequest asyncRequest, IAsyncResult transportResult)
156                 {
157                         try {
158                                 _SslState.InnerStream.EndWrite (transportResult);
159                         } catch (Exception e) {
160                                 _SslState.FinishWrite ();
161                                 if (!asyncRequest.IsUserCompleted) {
162                                         asyncRequest.CompleteWithError (e);
163                                         return;
164                                 }
165                                 throw;
166                         }
167
168                         if (asyncRequest.State == HandshakeProtocolState.SendHelloRequest) {
169                                 asyncRequest.SetNextRequest (HandshakeProtocolState.ServerRenegotiation, null, _ResumeHandshakeWriteCallback);
170                                 StartHandshakeWrite (asyncRequest);
171                                 return;
172                         }
173
174                         try {
175                                 _SslState.FinishWrite ();
176                                 asyncRequest.CompleteUser ();
177                         } catch (Exception e) {
178                                 if (!asyncRequest.IsUserCompleted) {
179                                         asyncRequest.CompleteWithError (e);
180                                         return;
181                                 }
182                                 throw;
183                         }
184                 }
185
186                 static void ResumeHandshakeWriteCallback (HandshakeProtocolRequest asyncRequest)
187                 {
188                         try {
189                                 ((_SslStream)asyncRequest.AsyncObject).StartHandshakeWrite (asyncRequest);
190                         } catch (Exception e) {
191                                 if (asyncRequest.IsUserCompleted) {
192                                         // This will throw on a worker thread.
193                                         throw;
194                                 }
195                                 ((_SslStream)asyncRequest.AsyncObject)._SslState.FinishWrite ();
196                                 asyncRequest.CompleteWithError (e);
197                         }
198                 }
199
200                 delegate void HandshakeProtocolCallback (HandshakeProtocolRequest asyncRequest);
201
202                 enum HandshakeProtocolState {
203                         None,
204                         Shutdown,
205                         SendHelloRequest,
206                         ServerRenegotiation,
207                         ClientRenegotiation
208                 }
209
210                 class HandshakeProtocolRequest : AsyncProtocolRequest
211                 {
212                         public ProtocolToken Message;
213                         public HandshakeProtocolState State;
214
215                         public HandshakeProtocolRequest (LazyAsyncResult userAsyncResult)
216                                 : base (userAsyncResult)
217                         {
218                                 State = HandshakeProtocolState.None;
219                         }
220
221                         public void SetNextRequest (HandshakeProtocolState state, ProtocolToken message, HandshakeProtocolCallback callback)
222                         {
223                                 State = state;
224                                 Message = message;
225                                 SetNextRequest (null, 0, 0, (r) => callback ((HandshakeProtocolRequest)r));
226                         }
227                 }
228         }
229 }
230 #endif