AsyncOperationStatus ProcessClose(AsyncProtocolRequest asyncRequest, AsyncOperationStatus status) { Debug("ProcessClose: {0}", status); lock (ioLock) { if (xobileTlsContext == null) { return(AsyncOperationStatus.Complete); } xobileTlsContext.Close(); xobileTlsContext = null; return(AsyncOperationStatus.Continue); } }
int InternalRead(AsyncProtocolRequest asyncRequest, BufferOffsetSize internalBuffer, byte[] buffer, int offset, int size, out bool wantMore) { if (asyncRequest == null) { throw new InvalidOperationException(); } Debug("InternalRead: {0} {1} {2}", internalBuffer, offset, size); /* * One of Apple's native functions wants to read 'size' bytes of data. * * First, we check whether we already have enough in the internal buffer. * * If the internal buffer is empty (it will be the first time we're called), we save * the amount of bytes that were requested and return 'SslStatus.WouldBlock' to our * native caller. This native function will then return this code to managed code, * where we read the requested amount of data into the internal buffer, then call the * native function again. */ if (internalBuffer.Size == 0 && !internalBuffer.Complete) { Debug("InternalRead #1: {0} {1}", internalBuffer.Offset, internalBuffer.TotalBytes); internalBuffer.Offset = internalBuffer.Size = 0; asyncRequest.RequestRead(size); wantMore = true; return(0); } /* * The second time we're called, the native buffer will contain the exact amount of data that the * previous call requested from us, so we should be able to return it all here. However, just in * case that Apple's native function changed its mind, we can also return less. * * In either case, if we have any data buffered, then we return as much of it as possible - if the * native code isn't satisfied, then it will call us again to request more. */ var len = System.Math.Min(internalBuffer.Size, size); Buffer.BlockCopy(internalBuffer.Buffer, internalBuffer.Offset, buffer, offset, len); internalBuffer.Offset += len; internalBuffer.Size -= len; wantMore = !internalBuffer.Complete && len < size; return(len); }
public override void Close() { /* * SSLClose() is a little bit tricky as it might attempt to send a close_notify alert * and thus call our write callback. * * It is also not thread-safe with SSLRead() or SSLWrite(), so we need to take the I/O lock here. */ if (Interlocked.Exchange(ref closeRequested, 1) == 1) { return; } if (xobileTlsContext == null) { return; } var asyncRequest = new AsyncProtocolRequest(this, null); StartOperation(ref asyncWriteRequest, ref writeBuffer, ProcessClose, asyncRequest, "close"); }
AsyncOperationStatus ProcessHandshake(AsyncProtocolRequest asyncRequest, AsyncOperationStatus status) { Debug("ProcessHandshake: {0}", status); /* * The first time we're called (AsyncOperationStatus.Initialize), we need to setup the SslContext and * start the handshake. */ if (status == AsyncOperationStatus.Initialize) { xobileTlsContext.StartHandshake(); return(AsyncOperationStatus.Continue); } else if (status == AsyncOperationStatus.ReadDone) { // remote prematurely closed connection. throw new IOException("Remote prematurely closed connection."); } else if (status != AsyncOperationStatus.Continue) { throw new InvalidOperationException(); } /* * SSLHandshake() will return repeatedly with 'SslStatus.WouldBlock', we then need * to take care of I/O and call it again. */ if (!xobileTlsContext.ProcessHandshake()) { /* * Flush the internal write buffer. */ InnerFlush(); return(AsyncOperationStatus.Continue); } xobileTlsContext.FinishHandshake(); return(AsyncOperationStatus.Complete); }
AsyncOperationStatus ProcessWrite(AsyncProtocolRequest asyncRequest, AsyncOperationStatus status) { Debug("ProcessWrite - write user: {0} {1}", status, asyncRequest.UserBuffer); if (asyncRequest.UserBuffer.Size == 0) { asyncRequest.UserResult = asyncRequest.CurrentSize; return(AsyncOperationStatus.Complete); } int ret; bool wantMore; lock (ioLock) { ret = Context.Write(asyncRequest.UserBuffer.Buffer, asyncRequest.UserBuffer.Offset, asyncRequest.UserBuffer.Size, out wantMore); } Debug("ProcessWrite - write user done: {0} - {1} {2}", asyncRequest.UserBuffer, ret, wantMore); if (ret < 0) { asyncRequest.UserResult = -1; return(AsyncOperationStatus.Complete); } asyncRequest.CurrentSize += ret; asyncRequest.UserBuffer.Offset += ret; asyncRequest.UserBuffer.Size -= ret; if (wantMore || writeBuffer.Size > 0) { return(AsyncOperationStatus.WantWrite); } asyncRequest.ResetWrite(); asyncRequest.UserResult = asyncRequest.CurrentSize; return(AsyncOperationStatus.Complete); }
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 <int> StartOperation(OperationType type, AsyncProtocolRequest asyncRequest, CancellationToken cancellationToken) { CheckThrow(true, type != OperationType.Read); Debug("StartOperationAsync: {0} {1}", asyncRequest, type); if (type == OperationType.Read) { if (Interlocked.CompareExchange(ref asyncReadRequest, asyncRequest, null) != null) { throw GetInvalidNestedCallException(); } } else if (type == OperationType.Renegotiate) { 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(); } } else { if (Interlocked.CompareExchange(ref asyncWriteRequest, asyncRequest, null) != null) { throw GetInvalidNestedCallException(); } } AsyncProtocolResult result; try { lock (ioLock) { if (type == OperationType.Read) { readBuffer.Reset(); } else { writeBuffer.Reset(); } } result = await asyncRequest.StartOperation(cancellationToken).ConfigureAwait(false); } catch (Exception e) { var info = SetException(GetIOException(e, asyncRequest.Name + " failed")); result = new AsyncProtocolResult(info); } finally { lock (ioLock) { if (type == OperationType.Read) { readBuffer.Reset(); asyncReadRequest = null; } else if (type == OperationType.Renegotiate) { readBuffer.Reset(); writeBuffer.Reset(); asyncHandshakeRequest = null; asyncReadRequest = null; asyncWriteRequest = null; } else { writeBuffer.Reset(); asyncWriteRequest = null; } } } if (result.Error != null) { result.Error.Throw(); } return(result.UserResult); }
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(); } }
AsyncOperationStatus ProcessFlush(AsyncProtocolRequest asyncRequest, AsyncOperationStatus status) { Debug("ProcessFlush: {0}", status); return(AsyncOperationStatus.Complete); }
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; } } }