2 // Mono-specific additions to Microsoft's _SslStream.cs
4 #if MONO_FEATURE_NEW_TLS && SECURITY_DEP
5 namespace System.Net.Security
8 using System.Threading;
9 using System.Net.Sockets;
11 partial class _SslStream
13 static readonly AsyncCallback _HandshakeWriteCallback = new AsyncCallback (HandshakeWriteCallback);
14 static readonly HandshakeProtocolCallback _ResumeHandshakeWriteCallback = new HandshakeProtocolCallback (ResumeHandshakeWriteCallback);
16 internal void BeginShutdown (LazyAsyncResult lazyResult)
18 HandshakeProtocolRequest asyncRequest = new HandshakeProtocolRequest (lazyResult);
20 if (Interlocked.Exchange (ref _NestedWrite, 1) == 1)
21 throw new NotSupportedException (SR.GetString (SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginShutdown" : "Shutdown"), "shutdown"));
26 ProtocolToken message = _SslState.CreateShutdownMessage ();
27 asyncRequest.SetNextRequest (HandshakeProtocolState.Shutdown, message, _ResumeHandshakeWriteCallback);
29 StartHandshakeWrite (asyncRequest);
30 } catch (Exception e) {
31 _SslState.FinishWrite ();
40 internal void EndShutdown (LazyAsyncResult lazyResult)
42 if (Interlocked.Exchange (ref _NestedWrite, 0) == 0)
43 throw new InvalidOperationException (SR.GetString (SR.net_io_invalidendcall, "EndShutdown"));
45 // No "artificial" timeouts implemented so far, InnerStream controls timeout.
46 lazyResult.InternalWaitForCompletion ();
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);
55 internal void BeginRenegotiate (LazyAsyncResult lazyResult)
57 HandshakeProtocolRequest asyncRequest = new HandshakeProtocolRequest (lazyResult);
59 if (Interlocked.Exchange (ref _NestedWrite, 1) == 1)
60 throw new NotSupportedException (SR.GetString (SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginRenegotiate" : "Renegotiate"), "renegotiate"));
65 if (_SslState.IsServer) {
66 ProtocolToken message = _SslState.CreateHelloRequestMessage ();
67 asyncRequest.SetNextRequest (HandshakeProtocolState.SendHelloRequest, message, _ResumeHandshakeWriteCallback);
69 asyncRequest.SetNextRequest (HandshakeProtocolState.ClientRenegotiation, null, _ResumeHandshakeWriteCallback);
72 StartHandshakeWrite (asyncRequest);
73 } catch (Exception e) {
74 _SslState.FinishWrite ();
83 internal void EndRenegotiate (LazyAsyncResult lazyResult)
85 if (Interlocked.Exchange (ref _NestedWrite, 0) == 0)
86 throw new InvalidOperationException (SR.GetString (SR.net_io_invalidendcall, "EndRenegotiate"));
88 // No "artificial" timeouts implemented so far, InnerStream controls timeout.
89 lazyResult.InternalWaitForCompletion();
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);
98 void StartHandshakeWrite (HandshakeProtocolRequest asyncRequest)
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);
109 switch (asyncRequest.State) {
110 case HandshakeProtocolState.ClientRenegotiation:
111 case HandshakeProtocolState.ServerRenegotiation:
112 _SslState.StartReHandshake (asyncRequest);
115 case HandshakeProtocolState.SendHelloRequest:
116 if (_SslState.CheckEnqueueHandshakeWrite (buffer, asyncRequest)) {
117 // operation is async and has been queued, return.
122 case HandshakeProtocolState.Shutdown:
123 if (_SslState.CheckEnqueueWrite (asyncRequest)) {
124 // operation is async and has been queued, return.
130 throw new InvalidOperationException ();
133 if (_SslState.LastPayload != null)
134 throw new InvalidOperationException ();
136 // prepare for the next request
137 IAsyncResult ar = ((NetworkStream)_SslState.InnerStream).BeginWrite (buffer, 0, buffer.Length, _HandshakeWriteCallback, asyncRequest);
138 if (!ar.CompletedSynchronously)
141 HandshakeWriteCallback (asyncRequest, ar);
144 static void HandshakeWriteCallback (IAsyncResult transportResult)
146 if (transportResult.CompletedSynchronously)
149 HandshakeProtocolRequest asyncRequest = (HandshakeProtocolRequest)transportResult.AsyncState;
151 SslState sslState = (SslState)asyncRequest.AsyncObject;
152 sslState.SecureStream.HandshakeWriteCallback (asyncRequest, transportResult);
155 void HandshakeWriteCallback (HandshakeProtocolRequest asyncRequest, IAsyncResult transportResult)
158 _SslState.InnerStream.EndWrite (transportResult);
159 } catch (Exception e) {
160 _SslState.FinishWrite ();
161 if (!asyncRequest.IsUserCompleted) {
162 asyncRequest.CompleteWithError (e);
168 if (asyncRequest.State == HandshakeProtocolState.SendHelloRequest) {
169 asyncRequest.SetNextRequest (HandshakeProtocolState.ServerRenegotiation, null, _ResumeHandshakeWriteCallback);
170 StartHandshakeWrite (asyncRequest);
175 _SslState.FinishWrite ();
176 asyncRequest.CompleteUser ();
177 } catch (Exception e) {
178 if (!asyncRequest.IsUserCompleted) {
179 asyncRequest.CompleteWithError (e);
186 static void ResumeHandshakeWriteCallback (HandshakeProtocolRequest asyncRequest)
189 ((_SslStream)asyncRequest.AsyncObject).StartHandshakeWrite (asyncRequest);
190 } catch (Exception e) {
191 if (asyncRequest.IsUserCompleted) {
192 // This will throw on a worker thread.
195 ((_SslStream)asyncRequest.AsyncObject)._SslState.FinishWrite ();
196 asyncRequest.CompleteWithError (e);
200 delegate void HandshakeProtocolCallback (HandshakeProtocolRequest asyncRequest);
202 enum HandshakeProtocolState {
210 class HandshakeProtocolRequest : AsyncProtocolRequest
212 public ProtocolToken Message;
213 public HandshakeProtocolState State;
215 public HandshakeProtocolRequest (LazyAsyncResult userAsyncResult)
216 : base (userAsyncResult)
218 State = HandshakeProtocolState.None;
221 public void SetNextRequest (HandshakeProtocolState state, ProtocolToken message, HandshakeProtocolCallback callback)
225 SetNextRequest (null, 0, 0, (r) => callback ((HandshakeProtocolRequest)r));