text: #ifndef SQ_OPENSSL_OVERLAY_H
  #define SQ_OPENSSL_OVERLAY_H 1
  /****************************************************************************
   *   PROJECT: SqueakSSL implementation for Linux/Unix
   *   FILE:    openssl_overlay.h
   *   CONTENT: Overlay OpenSSL for Linux/Unix
   *
   *   AUTHORS: Tobias Pape (topa)
   *               Hasso Plattner Institute, Potsdam, Germany
   *****************************************************************************
   *   When we dynamically link against OpenSSL, the bundles are not
   *   portable, as CentOS and friends use other SO_NAMEs than Debian and
   *   friends. Also, soft-fallback for later features such as host name
   *   verification is hard.
   *
   * This overlay supports using OpenSSL from 0.9.8 to at least 1.1 at runtime.
   *
   *   When we statically link, we might lack behind the OS, the binaries
   *   are bigger, and the legal situation is less clear.
   *
   *   So we now support not linking at all but rather lookup all necessary
   *   functions/symbols at runtime.
   *
   *   This can be disabled with SQSSL_OPENSSL_LINKED which effectively
   *   results in the dynamically-linked behavior. (This is preferable for
   *   platform builds, eg, debs and rpms)
   *****************************************************************************/
  #include <stdbool.h>
  #include <stdint.h>
  #include <stdlib.h>
  #include <stdio.h>
  
  #include <openssl/ssl.h>
  #include <openssl/err.h>
  #include <openssl/x509v3.h>
  
  
  
  /*
   * Debug helper
   */
  #if (defined(DEBUG) || (defined(DEBUGVM) && DEBUGVM==1)) && !defined(NDEBUG)
  #define DEBUG_PRINT(X, ...) fprintf(stderr, X, __VA_ARGS__)
  #else
  #define DEBUG_PRINT(X, ...)
  #endif
  
  #define NULL_FUNC ((void*(*)())NULL)
  
  /**********************************************************************/
  #if defined(SQSSL_OPENSSL_LINKED)
  /**********************************************************************/
  /*
   *      If we are working linked, we do not do any magic.
   *      In fact, we just re-wire the sqo_ names to their actual ones and
   *      unavailiable ones to NULL
   */
  /**********************************************************************/
  #define sqo_ASN1_STRING_length ASN1_STRING_length
  #define sqo_BIO_free_all BIO_free_all
  #define sqo_BIO_new BIO_new
  #define sqo_BIO_s_mem BIO_s_mem
  #define sqo_BIO_ctrl_pending BIO_ctrl_pending
  #define sqo_BIO_set_close BIO_set_close
  #define sqo_BIO_ctrl BIO_ctrl
  #define sqo_BIO_write BIO_write
  #define sqo_BIO_read BIO_read
  #define sqo_ERR_print_errors_fp ERR_print_errors_fp
  #define sqo_SSL_CTX_new SSL_CTX_new
  #define sqo_SSL_CTX_free SSL_CTX_free
  #define sqo_SSL_CTX_set_cipher_list SSL_CTX_set_cipher_list
  #define sqo_SSL_CTX_set_default_verify_paths SSL_CTX_set_default_verify_paths
  #define sqo_SSL_CTX_ctrl SSL_CTX_ctrl
  #define sqo_SSL_CTX_use_PrivateKey_file SSL_CTX_use_PrivateKey_file
  #define sqo_SSL_CTX_use_certificate_file SSL_CTX_use_certificate_file
  #define sqo_SSL_accept SSL_accept
  #define sqo_SSL_connect SSL_connect
  #define sqo_SSL_free SSL_free
  #define sqo_SSL_ctrl SSL_ctrl
  #define sqo_SSL_get_error SSL_get_error
  #if OPENSSL_VERSION_NUMBER >= 0x30000000L
  #define sqo_SSL_get_peer_certificate SSL_get1_peer_certificate
  #define sqo_SSL_get1_peer_certificate SSL_get1_peer_certificate
  #else
  #define sqo_SSL_get_peer_certificate SSL_get_peer_certificate
  #define sqo_SSL_get1_peer_certificate NULL_FUNC
  #endif
  #define sqo_SSL_get_verify_result SSL_get_verify_result
  #define sqo_SSL_new SSL_new
  #define sqo_SSL_read SSL_read
  #define sqo_SSL_set_accept_state SSL_set_accept_state
  #define sqo_SSL_set_bio SSL_set_bio
  #define sqo_SSL_set_connect_state SSL_set_connect_state
  #define sqo_SSL_set_tlsext_host_name SSL_set_tlsext_host_name
  #define sqo_SSL_write SSL_write
  #define sqo_X509_NAME_get_text_by_NID X509_NAME_get_text_by_NID
  #define sqo_X509_get_subject_name X509_get_subject_name
  #define sqo_X509_get_ext_d2i X509_get_ext_d2i
  #define sqo_X509_free X509_free
  
  #define sqo_SKM_sk_num SKM_sk_num
  #define sqo_SKM_sk_value SKM_sk_value
  #define sqo_SKM_sk_free SKM_sk_free
  #define sqo_SKM_sk_pop_free SKM_sk_pop_free
  #define sqo_sk_GENERAL_NAME_num sk_GENERAL_NAME_num
  #define sqo_sk_GENERAL_NAME_value sk_GENERAL_NAME_value
  #define sqo_sk_GENERAL_NAME_free sk_GENERAL_NAME_free
  #define sqo_sk_GENERAL_NAME_pop_free sk_GENERAL_NAME_pop_free
  
  #if OPENSSL_VERSION_NUMBER >= 0x10002000L
  #define sqo_SSL_CTX_set_options SSL_CTX_set_options
  #define sqo_X509_check_ip_asc X509_check_ip_asc
  #define sqo_X509_check_host X509_check_host
  #elif  OPENSSL_VERSION_NUMBER < 0x10002000L
  #define sqo_X509_check_ip_asc NULL_FUNC
  #define sqo_X509_check_host NULL_FUNC
  #endif
  
  #if OPENSSL_VERSION_NUMBER >= 0x10100000L
  #define sqo_SSL_CTX_set_options SSL_CTX_set_options
  #define sqo_BIO_test_flags BIO_test_flags
  #define sqo_OPENSSL_init_ssl OPENSSL_init_ssl
  #define sqo_OPENSSL_sk_new_null OPENSSL_sk_new_null
  #define sqo_OPENSSL_sk_push OPENSSL_sk_push
  #define sqo_OPENSSL_sk_free OPENSSL_sk_free
  #define sqo_OPENSSL_sk_value OPENSSL_sk_value
  #define sqo_OPENSSL_sk_num OPENSSL_sk_num
  #define sqo_OPENSSL_sk_pop_free OPENSSL_sk_pop_free
  #define sqo_TLS_method TLS_method
  
  #define sqo_ASN1_STRING_get0_data ASN1_STRING_get0_data
  #define sqo_ASN1_STRING_data NULL_FUNC
  
  #define sqo_sk_new_null NULL_FUNC
  #define sqo_sk_push NULL_FUNC
  #define sqo_sk_free NULL_FUNC
  #define sqo_sk_value NULL_FUNC
  #define sqo_sk_num NULL_FUNC
  #define sqo_sk_pop_free NULL_FUNC
  #define sqo_SSLv23_method NULL_FUNC
  
  #define sqo_SSL_library_init NULL_FUNC
  #define sqo_SSL_load_error_strings NULL_FUNC
  
  #elif OPENSSL_VERSION_NUMBER < 0x10100000L
  
  // do not #define sqo_SSL_CTX_set_options, is already
  #define sqo_BIO_test_flags NULL_FUNC
  #define sqo_OPENSSL_init_ssl NULL_FUNC
  #define sqo_OPENSSL_sk_new_null NULL_FUNC
  #define sqo_OPENSSL_sk_push NULL_FUNC
  #define sqo_OPENSSL_sk_free NULL_FUNC
  #define sqo_OPENSSL_sk_value NULL_FUNC
  #define sqo_OPENSSL_sk_num NULL_FUNC
  #define sqo_OPENSSL_sk_pop_free NULL_FUNC
  #define sqo_TLS_method NULL_FUNC
  
  #define sqo_ASN1_STRING_get0_data NULL_FUNC
  
  #define sqo_ASN1_STRING_data ASN1_STRING_data
  
  #define sqo_sk_new_null sk_new_null
  #define sqo_sk_push sk_push
  #define sqo_sk_free sk_free
  #define sqo_sk_value sk_value
  #define sqo_sk_num sk_num
  #define sqo_sk_pop_free sk_pop_free
  #define sqo_SSLv23_method SSLv23_method
  
  #define sqo_SSL_library_init SSL_library_init
  #define sqo_SSL_load_error_strings SSL_load_error_strings
  
  #define sk_GENERAL_NAME_freefunc void(*)(GENERAL_NAME*)
  
  #endif
  
  /**********************************************************************/
  /**********************************************************************/
  /**********************************************************************/
  /**********************************************************************/
  /**********************************************************************/
  /**********************************************************************/
  #elif !defined(SQSSL_OPENSSL_LINKED)
  /**********************************************************************/
  /* Welcome to dynamic loading land, where the declarations are made up and the
   * pointers do not matter.
   */
  /**********************************************************************/
  /**********************************************************************/
  /**********************************************************************/
  /**********************************************************************/
  /**********************************************************************/
  /**********************************************************************/
  
  #if OPENSSL_VERSION_NUMBER < 0x10100000L
  #  define OPENSSL_STACK _STACK
  #  define sk_GENERAL_NAME_freefunc void(*)(GENERAL_NAME*)
  #  define OPENSSL_INIT_SETTINGS struct ossl_init_settings_st
  OPENSSL_INIT_SETTINGS;
  
  #if !defined(inline)
  #  if defined(__GNUC__)
  #    define ossl_inline __inline__
  #  else
  #    define ossl_inline /**/
  #  endif
  #else
  #  define ossl_inline inline
  #endif
  
  # else
  #  define _STACK OPENSSL_STACK
  #  define STACK OPENSSL_STACK
  #  define CHECKED_STACK_OF(type, st) (OPENSSL_STACK*)st
  # endif
  
  /*
   * List of all used OpenSSL functions in the following format:
   *
   * SQO_DECL___(RETURN_TYPE, NAME, ARGS...)
   *
   * For symbols that appeared first version XYZ (X >=1) use SQO_DECLXYZ,
   * for example:
   *
   * SQO_DECL102 (Available since OpenSSL 1.0.2)
   *     (NAME will have value NULL in OpenSSL < 1.0.2)
   *
   * SPECIAL CASE FOR OLD OPENSSL
   * For symbols with different types in 0.9.8 / 1.0.0 use:
   *
   * SQO_DECL098 (OpenSSL <= 0.9.8)
   *    (NAME will not be defined in > 0.9.8)
   * SQO_DECL100 (OpenSSL >= 1.0.0)
   *    (NAME will not be defined in < 1.0.0)
   * SQO_DECL110 (OpenSSL >= 1.1.0)
   *    (NAME will not be defined in < 1.1.0)
   *
   */
  #define SQO_DECLARATIONS                                                \
    /**/                                                                  \
    SQO_DECL___(unsigned char *, ASN1_STRING_data, ASN1_STRING *x)        \
    SQO_DECL___(int, ASN1_STRING_length, const ASN1_STRING *x)            \
    SQO_DECL___(void, BIO_free_all, BIO *a)                               \
    SQO_DECL___(BIO *, BIO_new, BIO_METHOD *type)                         \
    SQO_DECL___(BIO_METHOD *, BIO_s_mem, void)                            \
    SQO_DECL___(size_t, BIO_ctrl_pending, BIO *bp)                        \
    SQO_DECL___(long, BIO_ctrl, BIO *bp, int cmd, long larg, void *parg)  \
    SQO_DECL___(int, BIO_write, BIO *b, const void *data, int len)        \
    SQO_DECL___(int, BIO_read, BIO *b, void *data, int len)               \
    SQO_DECL___(void, ERR_print_errors_fp, FILE *fp)                      \
    SQO_DECL___(void, SSL_CTX_free, SSL_CTX *)                            \
    SQO_DECL___(int, SSL_CTX_set_cipher_list, SSL_CTX *, const char *str) \
    SQO_DECL___(int, SSL_CTX_set_default_verify_paths, SSL_CTX *ctx)      \
    SQO_DECL___(long, SSL_CTX_ctrl, SSL_CTX *ctx, int cmd, long larg, void *parg) \
    SQO_DECL___(int, SSL_CTX_use_PrivateKey_file, SSL_CTX *ctx, const char *file, int type) \
    SQO_DECL___(int, SSL_CTX_use_certificate_file, SSL_CTX *ctx, const char *file, int type) \
    SQO_DECL___(int, SSL_accept, SSL *ssl)                                \
    SQO_DECL___(int, SSL_connect, SSL *ssl)                               \
    SQO_DECL___(void, SSL_free, SSL *ssl)                                 \
    SQO_DECL___(long, SSL_ctrl, SSL *ssl, int cmd, long larg, void *parg) \
    SQO_DECL___(int, SSL_get_error, const SSL *s, int ret_code)           \
    SQO_DECL_IF(X509 *, SSL_get_peer_certificate, const SSL *s)           \
    SQO_DECL_IF(X509 *, SSL_get1_peer_certificate, const SSL *s)          \
    SQO_DECL___(long, SSL_get_verify_result, const SSL *ssl)              \
    SQO_DECL___(SSL *, SSL_new, SSL_CTX *ctx)                             \
    SQO_DECL___(int, SSL_read, SSL *ssl, void *buf, int num)              \
    SQO_DECL___(void, SSL_set_accept_state, SSL *s)                       \
    SQO_DECL___(void, SSL_set_bio, SSL *s, BIO *rbio, BIO *wbio)          \
    SQO_DECL___(void, SSL_set_connect_state, SSL *s)                      \
    SQO_DECL___(int, SSL_write, SSL *ssl, const void *buf, int num)       \
    SQO_DECL___(int, X509_NAME_get_text_by_NID, X509_NAME *name, int nid, char *buf, int len) \
    SQO_DECL___(X509_NAME *, X509_get_subject_name, X509 *a)              \
    SQO_DECL___(void *, X509_get_ext_d2i, X509 *x, int nid, int *crit, int *idx) \
    SQO_DECL___(void, X509_free, X509 *ssl)                               \
                                                                          \
    SQO_DECL102(int, X509_check_ip_asc, X509 *x, const char *ipasc, unsigned int flags) \
    SQO_DECL102(int, X509_check_host, X509 *x, const char *chk, size_t chklen, unsigned int flags, char **peername) \
                                                                          \
    SQO_DECL110(unsigned long, SSL_CTX_set_options, SSL_CTX *ctx, unsigned long op) \
    SQO_DECL110(int, BIO_test_flags, const BIO *b, int flags)             \
                                                                          \
    SQO_DECL110(const unsigned char *, ASN1_STRING_get0_data, const ASN1_STRING *x) \
                                                                          \
    SQO_DECL098(STACK *, sk_new_null, void)                               \
    SQO_DECL098(int, sk_push, STACK *st, char *data)                      \
    SQO_DECL098(void, sk_free, STACK *st)                                 \
    SQO_DECL098(char *, sk_value, STACK *st, int i)                       \
    SQO_DECL098(int, sk_num, STACK *st)                                   \
    SQO_DECL098(void, sk_pop_free, STACK *st, void (*func) (void *))      \
    SQO_DECL098(SSL_METHOD *, SSLv23_method, void)                        \
    SQO_DECL098(SSL_CTX *, SSL_CTX_new, SSL_METHOD *a)                    \
                                                                          \
    SQO_DECL100(_STACK *, sk_new_null, void)                              \
    SQO_DECL100(int, sk_push, _STACK *st, void *data)                     \
    SQO_DECL100(void, sk_free, _STACK *st)                                \
    SQO_DECL100(void *, sk_value, const _STACK *st, int i)                \
    SQO_DECL100(int, sk_num, const _STACK *st)                            \
    SQO_DECL100(void, sk_pop_free, _STACK *st, void (*func) (void *))     \
    SQO_DECL100(const SSL_METHOD *, SSLv23_method, void)                  \
    SQO_DECL100(SSL_CTX *, SSL_CTX_new, const SSL_METHOD *a)              \
                                                                          \
    SQO_DECL110(OPENSSL_STACK *, OPENSSL_sk_new_null, void)               \
    SQO_DECL110(int, OPENSSL_sk_push, OPENSSL_STACK *st, void *data)      \
    SQO_DECL110(void, OPENSSL_sk_free, OPENSSL_STACK *st)                 \
    SQO_DECL110(void *, OPENSSL_sk_value, const OPENSSL_STACK *st, int i) \
    SQO_DECL110(int, OPENSSL_sk_num, const OPENSSL_STACK *st)             \
    SQO_DECL110(void, OPENSSL_sk_pop_free, OPENSSL_STACK *st, void (*func) (void *)) \
    SQO_DECL110(SSL_METHOD *, TLS_method, void)                        \
                                                                          \
    SQO_DECL_IF(int, SSL_library_init, void)                              \
    SQO_DECL_IF(void, SSL_load_error_strings, void)                       \
    SQO_DECL110(int, OPENSSL_init_ssl, uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) \
    /* backstop */
  
  
  /***********************************************************************/
  /***********************************************************************/
  /***********************************************************************/
  /***********************************************************************/
  /***********************************************************************/
  /***********************************************************************/
  
  #if OPENSSL_VERSION_NUMBER >= 0x10000000L
  #define SQO_DECL098 SQO_DECL_NO
  #define SQO_DECL100 SQO_DECL_IF
  #else
  #define SQO_DECL098 SQO_DECL___
  #define SQO_DECL100 SQO_DECL_NO
  #endif
  #define SQO_DECL102 SQO_DECL_IF
  #define SQO_DECL110 SQO_DECL_IF
  
  /*
   *  WARNING: Here be dragons!
   *
   *  Only change things beyond this line if you know exactly what
   *  will happen.
   *
   *  The following stanzas will do this:
   *
   *  * When compiling non-linked (dynamically loaded):
   *    * find dl-header, define helper macros for symbol lookup
   *    * define static handles for dynamic libraries
   *    * helper function that does actual lookup
   *    * helper function that unloads libraries on SqueakSSL unload
   *
   *  * Declare all necessary OpenSSL symbols, prefixed with sqo_
   *
   *  * "loadLibrary" function to be called once by SqueakSSL:
   *    * When compiling linked (not dynamically loaded):
   *      * alias all necessary OpenSSL symbols to sqo_ prefixed
   *    * otherwise, when compiling non-linked (dynamically loaded):
   *      * lookup every symbol and assign to sqo_ prefixed name
   *
   *  That's it, essentially.
   */
  
  
  /**********************************************************************/
  #include <dlfcn.h>
  
  #if !defined(SQO_DL_FLAGS)
  #  if !defined(__OpenBSD__)
  #    define SQO_DL_FLAGS (RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE)
  #  else
  #    define SQO_DL_FLAGS (RTLD_NOW | RTLD_GLOBAL)
  #  endif
  #endif /* !defined(SQO_DL_FLAGS) */
  
  /*
   * Handles for the dlopen'ed dynamic libraries
   *
   */
  static void* dlhandle_self = NULL;
  static void* dlhandle_crypto = NULL;
  static void* dlhandle_ssl = NULL;
  
  
  /*
   * Helpers to make sure the loaded library handles are closed when
   * this module is unloaded (w/ care for at lease GCC and llvm/clang)
   */
  #if !defined(__has_attribute)
  #define __has_attribute(x) 0
  #endif
  
  #if __has_attribute(destructor) \
    || defined(__GNUC__)
  #define SQO_DESTRUCTOR __attribute__((destructor))
  #else
  #define SQO_DESTRUCTOR /**/
  #endif
  
  void SQO_DESTRUCTOR fini(void)
  {
  #if defined(RTLD_NODELETE)
    if (!(SQO_DL_FLAGS & RTLD_NODELETE)) {
  #endif
      if (dlhandle_self) { dlclose(dlhandle_self); }
      if (dlhandle_crypto) { dlclose(dlhandle_crypto); }
      if (dlhandle_ssl) { dlclose(dlhandle_ssl);}
  #if defined(RTLD_NODELETE)
    }
  #endif
  }
  
  
  /*
   * It may be the case that the libs we try to load are not exactly named as we like
   * So we
   *  * enumerate all plausible library paths
   *  * enumerate all libs there matching our name
   * * and report back the _names_ (NOT the full paths, we want dlopen to
   *      consider whaterver it has to)
   */
  
  /*
   * The Paths part >>
   */
  #if !defined(__MACH__)
  /* This is to find possible library locations. */
  
  #include <limits.h>
  #include <link.h>
  #include <glob.h>
  #include <libgen.h>
  
  #define _SQO_MAX_LIBS 32
  static char* _sqo_dynamic_lib_dirs[_SQO_MAX_LIBS] = { NULL };
  static size_t _sqo_dynamic_lib_dir_count = 0;
  
  static bool _sqo_insert_dynamic_lib_dir(char* dir)
  {
      bool found = false;
      for (size_t i  = 0; i < _sqo_dynamic_lib_dir_count; i ++) {
          if (strncmp(_sqo_dynamic_lib_dirs[i], dir, PATH_MAX) == 0) {
              found = true;
              break;
          }
      }
      if (!found) {
          _sqo_dynamic_lib_dirs[_sqo_dynamic_lib_dir_count++] = dir;
      }
      return found;
  }
  
  
  
  static int _sqo_find_lib_dirs(struct dl_phdr_info *info, size_t size, void *data)
  {
      if (info->dlpi_name[0] != '\0') {
          char* myname = strdup(info->dlpi_name);
          char* dir = dirname(myname);
          if (dir[0] == '.' && dir[1] == '\0') {
              // was empty
              free(myname);
          } else {
              if (_sqo_insert_dynamic_lib_dir(dir)) {
                  free(myname);
              }
          }
      }
      // Stop if we would go out of bounds.
      return !(_sqo_dynamic_lib_dir_count < _SQO_MAX_LIBS);
  }
  
  static void _sqo_dynamic_lib_dirs_reset(void)
  {
      for (size_t i = 0; i < _sqo_dynamic_lib_dir_count; i++) {
          free(_sqo_dynamic_lib_dirs[i]);
          _sqo_dynamic_lib_dirs[i] = NULL;
      }
      _sqo_dynamic_lib_dir_count = 0;
  }
  #undef _SQO_MAX_LIBS
  #endif // !__MACH__
  
  /*      Find all paths that may contain dynamic libraries.
   *      Returns their count. libs may be NULL to get allocation size
   */
  static size_t _sqo_lib_paths(size_t const n, char (*libs[n]))
  {
      size_t num_libs = 0;
      (void)(n);
  
  #define _SQO_ADD_LIB(L) do {                                          \
          DEBUG_PRINT("Library path %zu at %s\n", num_libs, L);        \
          if (libs != NULL) libs[num_libs] = strdup(L);                \
          num_libs++;                                                     \
      } while (0)
      /*
       *  Add all paths on the LD_LIBRARY_PATH
       */
      char* ld_library_path = getenv("LD_LIBRARY_PATH");
      if (ld_library_path != NULL) {
          if (libs == NULL) {
              /* just count */
              for (char* in_llp = ld_library_path; *in_llp != '\0'; in_llp++) {
                  if (*in_llp == ':' || *in_llp == ';') {
                      num_libs++;
                  }
              }
          } else {
              char* current = NULL, *tofree, *path;
              tofree = path = strdup(ld_library_path);
              while ((path != NULL) && ((current = strsep(&path, ":;")) != NULL)) {
                  if (*current != '\0') {
                      _SQO_ADD_LIB(current);
                  }
              }
              free(tofree);
          }
      }
  
  #if !defined(__MACH__)
      if (_sqo_dynamic_lib_dirs[0] == NULL) {
          dl_iterate_phdr(&_sqo_find_lib_dirs, NULL);
      }
      for (size_t i = 0; i < _sqo_dynamic_lib_dir_count; i++) {
          _SQO_ADD_LIB(_sqo_dynamic_lib_dirs[i]);
      }
  #endif //!defined(__MACH__)
  
      _SQO_ADD_LIB("/lib");
      _SQO_ADD_LIB("/usr/lib");
      _SQO_ADD_LIB("/usr/local/lib");
  #if INTPTR_MAX == INT32_MAX
      _SQO_ADD_LIB("/lib32");
      _SQO_ADD_LIB("/usr/lib32");
      _SQO_ADD_LIB("/usr/local/lib32");
  #elif INTPTR_MAX == INT64_MAX
      _SQO_ADD_LIB("/lib64");
      _SQO_ADD_LIB("/usr/lib64");
      _SQO_ADD_LIB("/usr/local/lib64");
  #endif
  
      return num_libs;
  
  #undef _SQO_ADD_LIB
  }
  
  /*
   * << The Paths part
   * The Names part >>
   */
  
  #if defined(__linux__)
  static int (*_sqo_strverscmp)(const void* a, const void* b) =
      (int (*)(const void* a, const void* b))strverscmp;
  #else
  #include <ctype.h>
  static int _sqo_strverscmp(const char* a, const char* b)
  {
      char* left = (char*) a;
      char* right = (char*) b;
      while (*left && *right) {
          /* strcmp */
          while (*left && *right &&
                 !isdigit(*left) && !isdigit(*right) && *left == *right) {
              left++;
              right++;
          }
          if (!isdigit(*left) && !isdigit(*right)) {
              break;
          }
          long lnum = strtol(left, &left, 10);
          long rnum = strtol(right, &right, 10);
          if (lnum != rnum) {
              return lnum - rnum;
          }
      }
      return *left - *right;
  }
  #endif  /* defined(__linux__) */
  
  
  static int _sqo_versioncmp(const void* a, const void* b)
  {
      char* left = *((char**) a);
      char* right = *((char**) b);
      return _sqo_strverscmp(right, left);
  }
  
  /*
   *      enumerate all plausible paths and try the names found in numeric order.
   */
  void* _sqo_dlopen_any(const char* name, int mode)
  {
      size_t num_dirs = _sqo_lib_paths(0, NULL);
      char* dirs[num_dirs];
      _sqo_lib_paths(num_dirs, dirs);
      size_t name_len = strnlen(name, PATH_MAX);
  
  #define _SQO_MAX_LIBNAMES 64
      char* libnames[_SQO_MAX_LIBNAMES] = {NULL};
      size_t libname_count = 0;
  
      for (
           size_t dir_idx = 0;
           dir_idx < num_dirs && libname_count < _SQO_MAX_LIBNAMES;
           dir_idx++
      ) {
          char* possible_files  = NULL;
          int written = asprintf(&possible_files, "%s/%s.*", dirs[dir_idx], name);
          if (written <= 0) {
              continue;
          }
          glob_t g = {0};
          if (0 == glob(possible_files, GLOB_NOSORT, NULL, &g)) {
              if (g.gl_pathc > 0) {
                  for (size_t i = 0; i < g.gl_pathc; i++) {
                      char* fullfile = basename(g.gl_pathv[i]);
                      if (strnlen(fullfile, PATH_MAX) > name_len) {
                          libnames[libname_count] = strndup(fullfile, PATH_MAX);
                          libname_count++;
                      }
                  }
              }
              globfree(&g);
          }
          free(possible_files);
      }
      qsort(libnames,  libname_count, sizeof(char*), _sqo_versioncmp);
  
      void* handle = NULL;
      for (size_t i = 0; handle == NULL && i < libname_count; i++) {
          DEBUG_PRINT("Trying %s for %s\n", libnames[i], name);
          handle = dlopen(libnames[i], mode);
      }
      for (size_t i = 0; i < libname_count; i++) { free(libnames[i]); }
      return handle;
  }
  
  /*
   *      Try to open the openssl lib named _name_ in mode.
   *
   *      Zeroth, if name is NULL, go straight to dlopen.
   *      First, try the version most closely matching our compiletime version.
   *      Second, try the non-versioned bare name.
   *      Third, enumerate all plausible paths and try the names found
   *             in numeric order.
   */
  void* _sqo_dlopen(const char* name, int mode)
  {
      /* 0. */
      if (name == NULL) {
          return  dlopen(name, mode);
      }
      void* handle = NULL;
      /* 1. */
    #if defined(SHLIB_VERSION_NUMBER)
      char* newname = NULL;
      int written = asprintf(&newname, "%s." SHLIB_VERSION_NUMBER, name);
      if (written > 0) {
          if ((handle = dlopen(newname, mode)) != NULL) {
              DEBUG_PRINT("Found %s at %s\n", name, newname);
              free(newname);
              return handle;
          }
      }
  #endif
      /* 2. */
      if ((handle = dlopen(name, mode)) != NULL) {
          DEBUG_PRINT("Found %s proper\n", name);
          return handle;
      }
      /* 3. */
      return _sqo_dlopen_any(name, mode);
  }
  
  
    /*
   * Macro that lookups a symbol in a library and does immediately
   * return the address when found.
   *
   * (with optional debug output)
   */
  #define SQO_HAS_FOUND_SYM(s,n,h)                                \
      do {                                                        \
          if ((s = dlsym(h, n))) {                                \
              DEBUG_PRINT("Found symbol %s in " #h "\n", n);      \
              return s;                                           \
          }                                                       \
      } while (0)
  
  /*
   * Macro that lookups a symbol in a _named_ library.
   * Loads library if not yet done.
   * Uses SQO_HAS_FOUND_SYM, therefore immediately returns when found.
   */
  #define SQO_FIND_SYM(sym, name, where, dlname)                          \
      do {                                                                \
          if (!dlhandle_ ## where) {                                      \
              DEBUG_PRINT("Loading %s\n",(dlname)?(dlname):"self");       \
              dlhandle_ ## where = _sqo_dlopen(dlname, SQO_DL_FLAGS);     \
          }                                                               \
          if (dlhandle_ ## where) {                                       \
              SQO_HAS_FOUND_SYM(sym, name, dlhandle_ ## where);           \
          }                                                               \
      } while (0)
  
  /*
   * Find symbol named "name" in one of the following namespaces
   * (in order):
   *
   * 1. Already loaded dynamic objects
   * 2. The running executable itself
   * 3. libssl.so (as in OpenSSL)
   * 4. libcrypto.so (as in OpenSSL)
   */
  static inline void* _sqo_find(const char* name)
  {
    void* sym = NULL;
    SQO_HAS_FOUND_SYM(sym, name, RTLD_DEFAULT);
    SQO_FIND_SYM(sym, name, self, NULL);
    SQO_FIND_SYM(sym, name, ssl, "libssl.so");
    SQO_FIND_SYM(sym, name, crypto, "libcrypto.so");
    DEBUG_PRINT("Cannot find %s\n", name);
    return sym;
  }
  
  /*
   *
   *
   *
   *      DECLARE ALL NECESSARY SYMBOLS AS FOUND IN SQO_DECLARATIONS
   *
   *
   *
   *
   */
  #define SQO_DECL___(ret, name, ...) ret (*sqo_ ## name)(__VA_ARGS__) = NULL;
  #define SQO_DECL_IF(ret, name, ...) ret (*sqo_ ## name)(__VA_ARGS__) = NULL;
  #define SQO_DECL_NO(ret, name, ...) /**/
  
  /* THIS LINE IS VITAL */
  SQO_DECLARATIONS
  
  #undef SQO_DECL___
  #undef SQO_DECL_NO
  #undef SQO_DECL_IF
  
  
  /*
   * List of re-defined OpenSSL macros
   *
   * This is necessary to "redirect" the usage of un-prefixed symbols to
   * sqo_-prefixed ones.
   */
  
  #define sqo_BIO_set_close(b,c) (int)sqo_BIO_ctrl(b,BIO_CTRL_SET_CLOSE,(c),NULL)
  #define sqo_SSL_set_tlsext_host_name(s,name) sqo_SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)
  
  
  struct sqo_bio_st {
      void* _x1; void* _x2;  char* _x3; int _x4; int _x5;
      int flags;
  };
  
  static ossl_inline int sqo_BIO_should_retry(BIO* b){
      if (sqo_BIO_test_flags) {
          return sqo_BIO_test_flags(b, BIO_FLAGS_SHOULD_RETRY);
      } else {
          return ((struct sqo_bio_st*)b)->flags & BIO_FLAGS_SHOULD_RETRY;
      }
  }
  
  #if OPENSSL_VERSION_NUMBER < 0x10100000L
  
  #define sqo_SSL_CTX_set_options(ctx,op) sqo_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
  
  #define sqo_SKM_sk_num(type, st) sqo_sk_num(CHECKED_STACK_OF(type, st))
  #define sqo_SKM_sk_value(type, st,i) ((type *)sqo_sk_value(CHECKED_STACK_OF(type, st), i))
  #define sqo_SKM_sk_free(type, st) sqo_sk_free(CHECKED_STACK_OF(type, st))
  #define sqo_SKM_sk_pop_free(type, st, free_func) sqo_sk_pop_free(CHECKED_STACK_OF(type, st), CHECKED_SK_FREE_FUNC(type, free_func))
  #define sqo_sk_GENERAL_NAME_num(st) sqo_SKM_sk_num(GENERAL_NAME, (st))
  #define sqo_sk_GENERAL_NAME_value(st, i) sqo_SKM_sk_value(GENERAL_NAME, (st), (i))
  #define sqo_sk_GENERAL_NAME_free(st) sqo_SKM_sk_free(GENERAL_NAME, (st))
  #define sqo_sk_GENERAL_NAME_pop_free(st, free_func) sqo_SKM_sk_pop_free(GENERAL_NAME, (st), (free_func))
  # else
  static ossl_inline int
      sqo_sk_GENERAL_NAME_num(const STACK_OF(GENERAL_NAME)* sk)
  { return sqo_OPENSSL_sk_num((const OPENSSL_STACK*)sk);}
  static ossl_inline GENERAL_NAME*
      sqo_sk_GENERAL_NAME_value(const STACK_OF(GENERAL_NAME)* sk, int idx)
  { return (GENERAL_NAME*)sqo_OPENSSL_sk_value((const OPENSSL_STACK*)sk, idx);}
  static ossl_inline void
      sqo_sk_GENERAL_NAME_free(const STACK_OF(GENERAL_NAME)* sk)
  { return sqo_OPENSSL_sk_free((OPENSSL_STACK*)sk);}
  static ossl_inline void
      sqo_sk_GENERAL_NAME_pop_free(const STACK_OF(GENERAL_NAME)* sk, sk_GENERAL_NAME_freefunc f)
  { return sqo_OPENSSL_sk_pop_free((OPENSSL_STACK*)sk, (OPENSSL_sk_freefunc)f);}
  #endif
  
  #endif /* !defined(SQSSL_OPENSSL_LINKED) */
  /**********************************************************************/
  
  
  
  /*
   * List of optional OpenSSL constants
   *
   * This is necessary to allow usage of those constants with newer
   * dynamically loaded libraries, but whilst using older versions at
   * compile time.
   */
  #if defined(X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS)
  #define sqo_X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS
  #else
  #define sqo_X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10
  #endif
  
  #if defined(OPENSSL_INIT_LOAD_SSL_STRINGS)
  #define sqo_OPENSSL_INIT_LOAD_SSL_STRINGS OPENSSL_INIT_LOAD_SSL_STRINGS
  #else
  #define sqo_OPENSSL_INIT_LOAD_SSL_STRINGS 0x00000002L
  #endif
  
  #if defined(OPENSSL_INIT_LOAD_CRYPTO_STRINGS)
  #define sqo_OPENSSL_INIT_LOAD_CRYPTO_STRINGS OPENSSL_INIT_LOAD_CRYPTO_STRINGS
  #else
  #define sqo_OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L
  #endif
  
  #define sqo_SSL_ERROR_WANT_READ SSL_ERROR_WANT_READ
  #define sqo_SSL_ERROR_ZERO_RETURN SSL_ERROR_ZERO_RETURN
  
  #if defined(SSL_ERROR_WANT_X509_LOOKUP)
  #define sqo_SSL_ERROR_WANT_X509_LOOKUP SSL_ERROR_WANT_X509_LOOKUP
  #else
  #define sqo_SSL_ERROR_WANT_X509_LOOKUP 4
  #endif
  
  
  /*
   * Function that makes sure that all sqo_ prefixed OpenSSL names are
   * actually available.
   *
   * Returns
   *      true    when all required symbols could be loaded/are linked
   *      false   when at least one required symbol could not be loaded
   *
   * Call this exactly once!
   */
  bool loadLibrary(void)
  {
  #if !defined(SQSSL_OPENSSL_LINKED)
  /*
   *
   *
   *
   *      ASSING ALL NECESSARY SYMBOLS AS FOUND IN SQO_DECLARATIONS
   *
   *
   *
   *
   */
  #define SQO_DECL___(ret, name, ...) \
    if (!(sqo_ ## name = (ret (*)(__VA_ARGS__)) _sqo_find(#name)))      \
      return false;
  #define SQO_DECL_IF(ret, name, ...)                             \
    sqo_ ## name = (ret (*)(__VA_ARGS__)) _sqo_find(#name);
  #define SQO_DECL_NO(ret, name, ...) /**/
  
    /* THIS LINE IS VITAL */
    SQO_DECLARATIONS
  
  
  #undef SQO_DECL___
  #undef SQO_DECL_NO
  #undef SQO_DECL_IF
  
  #if !defined(SQSSL_OPENSSL_LINKED) && !defined(__MACH__)
    _sqo_dynamic_lib_dirs_reset();
  #endif
  
  #endif  /* defined(SQSSL_OPENSSL_LINKED) */
  
  
    if (sqo_SSL_library_init) {
        sqo_SSL_library_init();
        sqo_SSL_load_error_strings();
    } else if (sqo_OPENSSL_init_ssl) {
        sqo_OPENSSL_init_ssl(sqo_OPENSSL_INIT_LOAD_SSL_STRINGS |
                             sqo_OPENSSL_INIT_LOAD_CRYPTO_STRINGS,
                             NULL);
    } else {
        return false;
    }
  
    return true;
  }
  
  #undef SQO_DECLARATIONS
  
  
  /* !defined(SQ_OPENSSL_OVERLAY_H) */
  #endif
  /* EOF */
  