Esempio n. 1
0
        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);
            }
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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");
        }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        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;
                }
            }
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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();
            }
        }
Esempio n. 9
0
        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();
            }
        }
Esempio n. 10
0
 AsyncOperationStatus ProcessFlush(AsyncProtocolRequest asyncRequest, AsyncOperationStatus status)
 {
     Debug("ProcessFlush: {0}", status);
     return(AsyncOperationStatus.Complete);
 }
Esempio n. 11
0
        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;
                }
            }
        }