sogou / workflow

C++ Parallel Computing and Asynchronous Networking Framework
Apache License 2.0
12.98k stars 2.4k forks source link

在Android源码里面编译的问题 #889

Closed BDZNH closed 2 years ago

BDZNH commented 2 years ago

之前我在为 Android 平台编译里面写了在Android源码里面无法编译通过,当时我是通过预置 openssl 来间接绕过这个问题了。

现在贴一下具体的问题

问题1

int WFServerBase::init_ssl_ctx(const char *cert_file, const char *key_file)
{
    SSL_CTX *ssl_ctx = WFGlobal::new_ssl_server_ctx();

    if (!ssl_ctx)
        return -1;

    SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
    if (SSL_CTX_use_certificate_file(ssl_ctx, cert_file, SSL_FILETYPE_PEM) > 0 &&
        SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) > 0 &&
        SSL_CTX_set_tlsext_servername_callback(ssl_ctx, ssl_ctx_callback) > 0 &&
        SSL_CTX_set_tlsext_servername_arg(ssl_ctx, this) > 0)
    {
        this->set_ssl(ssl_ctx, this->params.ssl_accept_timeout);
        return 0;
    }

    SSL_CTX_free(ssl_ctx);
    return -1;
}

问题出现在 SSL_CTX_set_tlsext_servername_callback(ssl_ctx, ssl_ctx_callback) > 0 && 里面的 ssl_ctx_callback,boringssl 里面的原型定义是

int (*callback)(SSL *ssl, int *out_alert, void *arg)

但是 workflow 里面定义是

long ssl_ctx_callback(SSL *ssl, int *al, void *arg)

问题2

HttpTaskImpl.cc 里面的

static int __encode_auth(const char *p, std::string& auth)
{
    static SSL_CTX *init_ssl = WFGlobal::get_ssl_client_ctx();
    (void)init_ssl;
    BUF_MEM *bptr;
    BIO *bmem;
    BIO *b64;

    b64 = BIO_new(BIO_f_base64());
    if (b64)
    {
        bmem = BIO_new(BIO_s_mem());
        if (bmem)
        {
            BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
            b64 = BIO_push(b64, bmem);
            BIO_write(b64, p, strlen(p));
            (void)BIO_flush(b64);
            BIO_get_mem_ptr(b64, &bptr);

            if (bptr->length > 0)
            {
                auth.append("Basic ");
                auth.append(bptr->data, bptr->length);
            }

            BIO_free_all(b64);
            return 0;
        }

        BIO_free_all(b64);
    }

    return -1;
}

实际编译时报 BIO_f_base64() 未定义,看了下是因为 boringssl 里面,BIO_f_base64() 是弃用状态,Android 里面就没有把相应的实现编译到库里面。

一些解决方向

  1. 问题1 如果就 C/C++本身,这里加一些宏定义就能区分开,但是之前我在某处看到过你们说不太倾向于使用这种办法来区分,那么这种情况有没有什么比较好的办法
  2. 问题2
    • 修改Android源码规则,将 BIO_f_base64() 编译到(这样做实测可行,但是有VNDK 的api变动,可能有未知风险)
    • 使用其他的方式来代替这里的 openssl 的base64计算过程
BDZNH commented 2 years ago

看了下 openssl 里面的SSL_CTX_set_tlsext_servername_callback声明,见SSL_CTX_set_tlsext_servername_callback,它的第二个参数也是

int (*callback)(SSL *ssl, int *out_alert, void *arg)

workflow 里面定义的回调看起来本身就和 openssl 里面声明的不一致。

Barenboim commented 2 years ago

看了下 openssl 里面的SSL_CTX_set_tlsext_servername_callback声明,见SSL_CTX_set_tlsext_servername_callback,它的第二个参数也是

int (*callback)(SSL *ssl, int *out_alert, void *arg)

workflow 里面定义的回调看起来本身就和 openssl 里面声明的不一致。

😳 我检查一下。 如果不一致,编译应该出错才对。这两个类型完全不一样。

BDZNH commented 2 years ago

下面是具体的报错信息

external/workflow-0.10.1/src/server/WFServer.cc:78:3: error: no matching function for call to 'SSL_CTX_set_tlsext_servername_callback'
                SSL_CTX_set_tlsext_servername_callback(ssl_ctx, ssl_ctx_callback) > 0 &&
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
external/boringssl/src/include/openssl/ssl.h:4602:5: note: expanded from macro 'SSL_CTX_set_tlsext_servername_callback'
    SSL_CTX_set_tlsext_servername_callback
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
external/boringssl/src/include/openssl/ssl.h:2623:20: note: candidate function not viable: no known conversion from 'long (SSL *, int *, void *)' (aka 'long (ssl_st *, int *, void *)') to 'int (*)(SSL *, int *, void *)' (aka 'int (*)(ssl_st *, int *, void *)') for 2nd argument
OPENSSL_EXPORT int SSL_CTX_set_tlsext_servername_callback(
                   ^
1 error generated.
12:47:55 ninja failed with: exit status 1

应该确实是 workflow 里面声明出错了,Android 源码里面的默认的编译参数会执行更加严格的检查。下面是编译参数,看看是否有帮助

PWD=/proc/self/cwd prebuilts/clang/host/linux-x86/clang-r353983c/bin/clang++ -c -Wno-enum-compare -Wno-enum-compare-switch -Wno-null-pointer-arithmetic -Wno-null-dereference -Iexternal/workflow-0.10.1/src/include -Iexternal/workflow-0.10.1/src/manager -Iexternal/workflow-0.10.1/src/nameservice -Iexternal/workflow-0.10.1/src/protocol -Iexternal/workflow-0.10.1/src/client -Iexternal/workflow-0.10.1/src/server -Iexternal/workflow-0.10.1/src/protocol -Iexternal/workflow-0.10.1/src/server -Iexternal/workflow-0.10.1/src/protocol -Iexternal/workflow-0.10.1/src/server -Iexternal/workflow-0.10.1/src/algorithm -Iexternal/workflow-0.10.1/src/client -Iexternal/workflow-0.10.1/src/factory -Iexternal/workflow-0.10.1/src/kernel -Iexternal/workflow-0.10.1/src/manager -Iexternal/workflow-0.10.1/src/nameservice -Iexternal/workflow-0.10.1/src/protocol -Iexternal/workflow-0.10.1/src/server -Iexternal/workflow-0.10.1/src/util -Iexternal/workflow-0.10.1/src/kernel -Iexternal/workflow-0.10.1/src/util -Iexternal/workflow-0.10.1 -D__ANDROID_API__=29 -D__ANDROID_VNDK__  -Werror=implicit-function-declaration -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -no-canonical-prefixes -DNDEBUG -UDEBUG -fno-exceptions -Wno-multichar -O2 -g -fno-strict-aliasing -fdebug-prefix-map=/proc/self/cwd= -D__compiler_offsetof=__builtin_offsetof -faddrsig -Wimplicit-fallthrough -Werror=int-conversion -Wno-reserved-id-macro -Wno-format-pedantic -Wno-unused-command-line-argument -fcolor-diagnostics -Wno-zero-as-null-pointer-constant -Wno-sign-compare -Wno-defaulted-function-deleted -Wno-inconsistent-missing-override -ffunction-sections -fdata-sections -fno-short-enums -funwind-tables -fstack-protector-strong -Wa,--noexecstack -D_FORTIFY_SOURCE=2 -Wstrict-aliasing=2 -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Werror=date-time -Werror=format-security -nostdlibinc -m64 -march=x86-64 -DUSE_SSSE3 -mssse3 -msse4 -msse4.1 -msse4.2 -mpopcnt -Iexternal/boringssl/src/include -Iexternal/libcxx/include -Iexternal/libcxxabi/include -isystem out/soong/.intermediates/bionic/libc/libc.llndk/android_x86_64_vendor_shared/gen/include -isystem bionic/libc/kernel/android/uapi -isystem bionic/libc/kernel/uapi -isystem bionic/libc/kernel/uapi/asm-x86  -Wall -Werror -Wno-unused-parameter -Wno-unused-function -Wno-implicit-fallthrough -DUSE_BORINGSSL -target x86_64-linux-android -Bprebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/x86_64-linux-android/bin -fPIC -D_USING_LIBCXX -std=gnu++17 -Wsign-promo -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -Wno-thread-safety-negative -Wno-gnu-include-next -fvisibility-inlines-hidden -frtti  -Werror=int-to-pointer-cast -Werror=pointer-to-int-cast -Werror=address-of-temporary -Werror=return-type -Wno-tautological-constant-compare -Wno-tautological-type-limit-compare -Wno-tautological-unsigned-enum-zero-compare -Wno-tautological-unsigned-zero-compare -Wno-c++98-compat-extra-semi -Wno-return-std-move-in-c++11 -MD -MF out/soong/.intermediates/external/workflow-0.10.1/libworkflow/android_x86_64_vendor_static/obj/external/workflow-0.10.1/src/server/WFServer.o.d -o out/soong/.intermediates/external/workflow-0.10.1/libworkflow/android_x86_64_vendor_static/obj/external/workflow-0.10.1/src/server/WFServer.o external/workflow-0.10.1/src/server/WFServer.cc
Barenboim commented 2 years ago

看起来是我把SSL_CTX_set_tlsext_servername_callback的返回值和callback参数的返回值弄混了。我一会修一下。谢谢!

BDZNH commented 2 years ago

base64的问题,可以引入/集成第三方的实现,或者在 Util 里面实现一份,而不是用ssl的。看起来 boringssl 和openssl的base64部分,接口定义都不一样了。 解决回调问题和base64的问题,workflow应该就能无缝兼容Android了。

BDZNH commented 2 years ago

从 boringssl 的文档 base64.h 和 openssl 的文档 EVP_EncodeBlock 两者都共有的未弃用的 base64 编码的接口是 EVP_EncodeBlock __encode_auth 的实现可以这样代替

static int EVP_GetEncodedLength(size_t *out_len, size_t len) {
  if (len + 2 < len) {
    return 0;
  }
  len += 2;
  len /= 3;

  if (((len << 2) >> 2) != len) {
    return 0;
  }
  len <<= 2;

  if (len + 1 < len) {
    return 0;
  }
  len++;

  *out_len = len;
  return 1;
}
static int __encode_auth(const char *p, std::string& auth)
{
    int len = strlen(p);
    size_t encodelen;
    if(EVP_GetEncodedLength(&encodelen,len) == 1)
    {
        std::vector<uint8_t> out_vec(encodelen);
        uint8_t *out = out_vec.data();
        size_t outlen = EVP_EncodeBlock(out, (const uint8_t *)p, len);
        if (outlen > 0)
        {
            auth.append("Basic ");
            auth.append((char *)out, outlen);
            return 0;
        }
    }
    return -1;
}

看看这样是否可行 ?

Barenboim commented 2 years ago

https://github.com/sogou/workflow/pull/890 这个先修了。 openssl里把传进去的callback强转成返回值为void的函数指针,所以没有编译错误。

Barenboim commented 2 years ago

https://github.com/sogou/workflow/pull/892 Base64也改好了。麻烦帮我们试一下!

BDZNH commented 2 years ago

可以了,我这边实测可以无修改的情况下,无错误编译出来so,tutorial里面helloworld可以正常跑。 这个pull request看看还有啥问题没有 ?

894