Пример #1
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;
                }
            }
        }
Пример #2
0
        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);
        }
Пример #3
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;
                }
            }
        }
Пример #4
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();
            }
        }
Пример #5
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();
            }
        }
Пример #6
0
		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;
		}
Пример #7
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;
				}
			}
		}