int StartOperation(ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize2 internalBuffer, AsyncOperation operation, AsyncProtocolRequest asyncRequest, string name) { if (Interlocked.CompareExchange(ref nestedRequest, asyncRequest, null) != null) { throw new InvalidOperationException("Invalid nested call."); } bool failed = false; try { internalBuffer.Reset(); asyncRequest.StartOperation(operation); return(asyncRequest.UserResult); } catch (Exception e) { failed = true; if (e is IOException) { throw; } throw new IOException(name + " failed", e); } finally { if (asyncRequest.UserAsyncResult == null || failed) { internalBuffer.Reset(); nestedRequest = null; } } }
bool InternalWrite(AsyncProtocolRequest asyncRequest, BufferOffsetSize2 internalBuffer, byte[] buffer, int offset, int size) { Debug("InternalWrite: {0} {1} {2} {3}", asyncRequest != null, internalBuffer, offset, size); if (asyncRequest == null) { /* * The only situation where 'asyncRequest' could possibly be 'null' is when we're called * from within SSLClose() - which might attempt to send the close_notity notification. * Since this notification message is very small, it should definitely fit into our internal * buffer, so we just save it in there and after SSLClose() returns, the final call to * InternalFlush() - just before closing the underlying stream - will send it out. */ if (lastException != null) { return(false); } if (Interlocked.Exchange(ref closeRequested, 1) == 0) { internalBuffer.Reset(); } else if (internalBuffer.Remaining == 0) { throw new InvalidOperationException(); } } /* * Normal write - can be either SSLWrite() or SSLHandshake(). * * It is important that we always accept all the data and queue it. */ internalBuffer.AppendData(buffer, offset, size); /* * Calling 'asyncRequest.RequestWrite()' here ensures that ProcessWrite() is called next * time we regain control from native code. * * During the handshake, the native code won't actually realize (unless if attempts to send * so much that the write buffer gets full) that we only buffered the data. * * However, it doesn't matter because it will either return with a completed handshake * (and doesn't care whether the remote actually received the data) or it will expect more * data from the remote and request a read. In either case, we regain control in managed * code and can flush out the data. * * Note that a calling RequestWrite() followed by RequestRead() will first flush the write * queue once we return to managed code - before attempting to read anything. */ if (asyncRequest != null) { asyncRequest.RequestWrite(); } return(true); }
internal void ProcessAuthentication(LazyAsyncResult lazyResult) { var asyncRequest = new AsyncProtocolRequest(this, lazyResult); if (Interlocked.CompareExchange(ref asyncHandshakeRequest, asyncRequest, null) != null) { throw new InvalidOperationException("Invalid nested call."); } try { if (lastException != null) { throw lastException; } if (xobileTlsContext == null) { throw new InvalidOperationException(); } readBuffer.Reset(); writeBuffer.Reset(); try { asyncRequest.StartOperation(ProcessHandshake); } catch (Exception ex) { throw SetException(ex); } } finally { if (lazyResult == null || lastException != null) { readBuffer.Reset(); writeBuffer.Reset(); asyncHandshakeRequest = null; } } }
async Task ProcessAuthentication(bool runSynchronously, MonoSslAuthenticationOptions options, CancellationToken cancellationToken) { if (options.ServerMode) { if (options.ServerCertificate == null) { throw new ArgumentException(nameof(options.ServerCertificate)); } } else { if (options.TargetHost == null) { throw new ArgumentException(nameof(options.TargetHost)); } if (options.TargetHost.Length == 0) { options.TargetHost = "?" + Interlocked.Increment(ref uniqueNameInteger).ToString(NumberFormatInfo.InvariantInfo); } TargetHost = options.TargetHost; } if (lastException != null) { lastException.Throw(); } var asyncRequest = new AsyncHandshakeRequest(this, runSynchronously); if (Interlocked.CompareExchange(ref asyncHandshakeRequest, asyncRequest, null) != null) { throw GetInvalidNestedCallException(); } // Make sure no other async requests can be started during the handshake. if (Interlocked.CompareExchange(ref asyncReadRequest, asyncRequest, null) != null) { throw GetInvalidNestedCallException(); } if (Interlocked.CompareExchange(ref asyncWriteRequest, asyncRequest, null) != null) { throw GetInvalidNestedCallException(); } AsyncProtocolResult result; try { lock (ioLock) { if (xobileTlsContext != null) { throw new InvalidOperationException(); } readBuffer.Reset(); writeBuffer.Reset(); xobileTlsContext = CreateContext(options); } Debug($"ProcessAuthentication({(IsServer ? "server" : "client")})"); try { result = await asyncRequest.StartOperation(cancellationToken).ConfigureAwait(false); } catch (Exception ex) { result = new AsyncProtocolResult(SetException(GetSSPIException(ex))); } } finally { lock (ioLock) { readBuffer.Reset(); writeBuffer.Reset(); asyncWriteRequest = null; asyncReadRequest = null; asyncHandshakeRequest = null; } } if (result.Error != null) { result.Error.Throw(); } }
async Task ProcessAuthentication( bool runSynchronously, bool serverMode, string targetHost, SslProtocols enabledProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, bool clientCertRequired) { if (serverMode) { if (serverCertificate == null) { throw new ArgumentException(nameof(serverCertificate)); } } else { if (targetHost == null) { throw new ArgumentException(nameof(targetHost)); } if (targetHost.Length == 0) { targetHost = "?" + Interlocked.Increment(ref uniqueNameInteger).ToString(NumberFormatInfo.InvariantInfo); } } if (lastException != null) { lastException.Throw(); } var asyncRequest = new AsyncHandshakeRequest(this, runSynchronously); if (Interlocked.CompareExchange(ref asyncHandshakeRequest, asyncRequest, null) != null) { throw new InvalidOperationException("Invalid nested call."); } // Make sure no other async requests can be started during the handshake. if (Interlocked.CompareExchange(ref asyncReadRequest, asyncRequest, null) != null) { throw new InvalidOperationException("Invalid nested call."); } if (Interlocked.CompareExchange(ref asyncWriteRequest, asyncRequest, null) != null) { throw new InvalidOperationException("Invalid nested call."); } AsyncProtocolResult result; try { lock (ioLock) { if (xobileTlsContext != null) { throw new InvalidOperationException(); } readBuffer.Reset(); writeBuffer.Reset(); xobileTlsContext = CreateContext( serverMode, targetHost, enabledProtocols, serverCertificate, clientCertificates, clientCertRequired); } try { result = await asyncRequest.StartOperation(CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { result = new AsyncProtocolResult(SetException(GetSSPIException(ex))); } } finally { lock (ioLock) { readBuffer.Reset(); writeBuffer.Reset(); asyncWriteRequest = null; asyncReadRequest = null; asyncHandshakeRequest = null; } } if (result.Error != null) { result.Error.Throw(); } }
bool InternalWrite (AsyncProtocolRequest asyncRequest, BufferOffsetSize2 internalBuffer, byte[] buffer, int offset, int size) { Debug ("InternalWrite: {0} {1} {2} {3}", asyncRequest != null, internalBuffer, offset, size); if (asyncRequest == null) { /* * The only situation where 'asyncRequest' could possibly be 'null' is when we're called * from within SSLClose() - which might attempt to send the close_notity notification. * Since this notification message is very small, it should definitely fit into our internal * buffer, so we just save it in there and after SSLClose() returns, the final call to * InternalFlush() - just before closing the underlying stream - will send it out. */ if (lastException != null) return false; if (Interlocked.Exchange (ref closeRequested, 1) == 0) internalBuffer.Reset (); else if (internalBuffer.Remaining == 0) throw new InvalidOperationException (); } /* * Normal write - can be either SSLWrite() or SSLHandshake(). * * It is important that we always accept all the data and queue it. */ internalBuffer.AppendData (buffer, offset, size); /* * Calling 'asyncRequest.RequestWrite()' here ensures that ProcessWrite() is called next * time we regain control from native code. * * During the handshake, the native code won't actually realize (unless if attempts to send * so much that the write buffer gets full) that we only buffered the data. * * However, it doesn't matter because it will either return with a completed handshake * (and doesn't care whether the remote actually received the data) or it will expect more * data from the remote and request a read. In either case, we regain control in managed * code and can flush out the data. * * Note that a calling RequestWrite() followed by RequestRead() will first flush the write * queue once we return to managed code - before attempting to read anything. */ if (asyncRequest != null) asyncRequest.RequestWrite (); return true; }
int StartOperation (ref AsyncProtocolRequest nestedRequest, ref BufferOffsetSize2 internalBuffer, AsyncOperation operation, AsyncProtocolRequest asyncRequest, string name) { if (Interlocked.CompareExchange (ref nestedRequest, asyncRequest, null) != null) throw new InvalidOperationException ("Invalid nested call."); bool failed = false; try { internalBuffer.Reset (); asyncRequest.StartOperation (operation); return asyncRequest.UserResult; } catch (Exception e) { failed = true; if (e is IOException) throw; throw new IOException (name + " failed", e); } finally { if (asyncRequest.UserAsyncResult == null || failed) { internalBuffer.Reset (); nestedRequest = null; } } }