]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/jaegertracing/thrift/lib/d/src/thrift/async/ssl.d
import quincy beta 17.1.0
[ceph.git] / ceph / src / jaegertracing / thrift / lib / d / src / thrift / async / ssl.d
diff --git a/ceph/src/jaegertracing/thrift/lib/d/src/thrift/async/ssl.d b/ceph/src/jaegertracing/thrift/lib/d/src/thrift/async/ssl.d
deleted file mode 100644 (file)
index fe62426..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-module thrift.async.ssl;
-
-import core.thread : Fiber;
-import core.time : Duration;
-import std.array : empty;
-import std.conv : to;
-import std.exception : enforce;
-import std.socket;
-import deimos.openssl.err;
-import deimos.openssl.ssl;
-import thrift.base;
-import thrift.async.base;
-import thrift.async.socket;
-import thrift.internal.ssl;
-import thrift.internal.ssl_bio;
-import thrift.transport.base;
-import thrift.transport.ssl;
-
-/**
- * Provides SSL/TLS encryption for async sockets.
- *
- * This implementation should be considered experimental, as it context-switches
- * between fibers from within OpenSSL calls, and the safety of this has not yet
- * been verified.
- *
- * For obvious reasons (the SSL connection is stateful), more than one instance
- * should never be used on a given socket at the same time.
- */
-// Note: This could easily be extended to other transports in the future as well.
-// There are only two parts of the implementation which don't work with a generic
-// TTransport: 1) the certificate verification, for which peer name/address are
-// needed from the socket, and 2) the connection shutdown, where the associated
-// async manager is needed because close() is not usually called from within a
-// work item.
-final class TAsyncSSLSocket : TBaseTransport {
-  /**
-   * Constructor.
-   *
-   * Params:
-   *   context = The SSL socket context to use. A reference to it is stored so
-   *     that it does not get cleaned up while the socket is used.
-   *   transport = The underlying async network transport to use for
-   *     communication.
-   */
-  this(TAsyncSocket underlyingSocket, TSSLContext context) {
-    socket_ = underlyingSocket;
-    context_ = context;
-    serverSide_ = context.serverSide;
-    accessManager_ = context.accessManager;
-  }
-
-  override bool isOpen() @property {
-    if (ssl_ is null || !socket_.isOpen) return false;
-
-    auto shutdown = SSL_get_shutdown(ssl_);
-    bool shutdownReceived = (shutdown & SSL_RECEIVED_SHUTDOWN) != 0;
-    bool shutdownSent = (shutdown & SSL_SENT_SHUTDOWN) != 0;
-    return !(shutdownReceived && shutdownSent);
-  }
-
-  override bool peek() {
-    if (!isOpen) return false;
-    checkHandshake();
-
-    byte bt = void;
-    auto rc = SSL_peek(ssl_, &bt, bt.sizeof);
-    sslEnforce(rc >= 0, "SSL_peek");
-
-    if (rc == 0) {
-      ERR_clear_error();
-    }
-    return (rc > 0);
-  }
-
-  override void open() {
-    enforce(!serverSide_, "Cannot open a server-side SSL socket.");
-    if (isOpen) return;
-
-    if (ssl_) {
-      // If the underlying socket was automatically closed because of an error
-      // (i.e. close() was called from inside a socket method), we can land
-      // here with the SSL object still allocated; delete it here.
-      cleanupSSL();
-    }
-
-    socket_.open();
-  }
-
-  override void close() {
-    if (!isOpen) return;
-
-    if (ssl_ !is null) {
-      // SSL needs to send/receive data over the socket as part of the shutdown
-      // protocol, so we must execute the calls in the context of the associated
-      // async manager. On the other hand, TTransport clients expect the socket
-      // to be closed when close() returns, so we have to block until the
-      // shutdown work item has been executed.
-      import core.sync.condition;
-      import core.sync.mutex;
-
-      int rc = void;
-      auto doneMutex = new Mutex;
-      auto doneCond = new Condition(doneMutex);
-      synchronized (doneMutex) {
-        socket_.asyncManager.execute(socket_, {
-          rc = SSL_shutdown(ssl_);
-          if (rc == 0) {
-            rc = SSL_shutdown(ssl_);
-          }
-          synchronized (doneMutex) doneCond.notifyAll();
-        });
-        doneCond.wait();
-      }
-
-      if (rc < 0) {
-        // Do not throw an exception here as leaving the transport "open" will
-        // probably produce only more errors, and the chance we can do
-        // something about the error e.g. by retrying is very low.
-        logError("Error while shutting down SSL: %s", getSSLException());
-      }
-
-      cleanupSSL();
-    }
-
-    socket_.close();
-  }
-
-  override size_t read(ubyte[] buf) {
-    checkHandshake();
-    auto rc = SSL_read(ssl_, buf.ptr, cast(int)buf.length);
-    sslEnforce(rc >= 0, "SSL_read");
-    return rc;
-  }
-
-  override void write(in ubyte[] buf) {
-    checkHandshake();
-
-    // Loop in case SSL_MODE_ENABLE_PARTIAL_WRITE is set in SSL_CTX.
-    size_t written = 0;
-    while (written < buf.length) {
-      auto bytes = SSL_write(ssl_, buf.ptr + written,
-        cast(int)(buf.length - written));
-      sslEnforce(bytes > 0, "SSL_write");
-      written += bytes;
-    }
-  }
-
-  override void flush() {
-    checkHandshake();
-
-    auto bio = SSL_get_wbio(ssl_);
-    enforce(bio !is null, new TSSLException("SSL_get_wbio returned null"));
-
-    auto rc = BIO_flush(bio);
-    sslEnforce(rc == 1, "BIO_flush");
-  }
-
-  /**
-   * Whether to use client or server side SSL handshake protocol.
-   */
-  bool serverSide() @property const {
-    return serverSide_;
-  }
-
-  /// Ditto
-  void serverSide(bool value) @property {
-    serverSide_ = value;
-  }
-
-  /**
-   * The access manager to use.
-   */
-  void accessManager(TAccessManager value) @property {
-    accessManager_ = value;
-  }
-
-private:
-  /**
-   * If the condition is false, cleans up the SSL connection and throws the
-   * exception for the last SSL error.
-   */
-  void sslEnforce(bool condition, string location) {
-    if (!condition) {
-      // We need to fetch the error first, as the error stack will be cleaned
-      // when shutting down SSL.
-      auto e = getSSLException(location);
-      cleanupSSL();
-      throw e;
-    }
-  }
-
-  /**
-   * Frees the SSL connection object and clears the SSL error state.
-   */
-  void cleanupSSL() {
-    SSL_free(ssl_);
-    ssl_ = null;
-    ERR_remove_state(0);
-  }
-
-  /**
-   * Makes sure the SSL connection is up and running, and initializes it if not.
-   */
-  void checkHandshake() {
-    enforce(socket_.isOpen, new TTransportException(
-      TTransportException.Type.NOT_OPEN));
-
-    if (ssl_ !is null) return;
-    ssl_ = context_.createSSL();
-
-    auto bio = createTTransportBIO(socket_, false);
-    SSL_set_bio(ssl_, bio, bio);
-
-    int rc = void;
-    if (serverSide_) {
-      rc = SSL_accept(ssl_);
-    } else {
-      rc = SSL_connect(ssl_);
-    }
-    enforce(rc > 0, getSSLException());
-
-    auto addr = socket_.getPeerAddress();
-    authorize(ssl_, accessManager_, addr,
-      (serverSide_ ? addr.toHostNameString() : socket_.host));
-  }
-
-  TAsyncSocket socket_;
-  bool serverSide_;
-  SSL* ssl_;
-  TSSLContext context_;
-  TAccessManager accessManager_;
-}
-
-/**
- * Wraps passed TAsyncSocket instances into TAsyncSSLSockets.
- *
- * Typically used with TAsyncClient. As an unfortunate consequence of the
- * async client design, the passed transports cannot be statically verified to
- * be of type TAsyncSocket. Instead, the type is verified at runtime – if a
- * transport of an unexpected type is passed to getTransport(), it fails,
- * throwing a TTransportException.
- *
- * Example:
- * ---
- * auto context = nwe TSSLContext();
- * ... // Configure SSL context.
- * auto factory = new TAsyncSSLSocketFactory(context);
- *
- * auto socket = new TAsyncSocket(someAsyncManager, host, port);
- * socket.open();
- *
- * auto client = new TAsyncClient!Service(transport, factory,
- *   new TBinaryProtocolFactory!());
- * ---
- */
-class TAsyncSSLSocketFactory : TTransportFactory {
-  ///
-  this(TSSLContext context) {
-    context_ = context;
-  }
-
-  override TAsyncSSLSocket getTransport(TTransport transport) {
-    auto socket = cast(TAsyncSocket)transport;
-    enforce(socket, new TTransportException(
-      "TAsyncSSLSocketFactory requires a TAsyncSocket to work on, not a " ~
-      to!string(typeid(transport)) ~ ".",
-      TTransportException.Type.INTERNAL_ERROR
-    ));
-    return new TAsyncSSLSocket(socket, context_);
-  }
-
-private:
-  TSSLContext context_;
-}