从零开始成为GStreamer专家——HTTPS支持

GStreamer支持https,笔者使用了openssl库libsoup,glib-networking。openssl库的wrap文件下载位置位:

Meson WrapDB packages

libsoup可以看作是支持http/https协议的库,用glib的方式开发而成,连接管理都在里面完成。

Gstreamer TLS建立流程如下:


g_tls_connection_base_init 行 236                 subprojects\glib-networking\tls\base\gtlsconnection-base.c(236)
g_initable_new 行 168                             subprojects\glib\gio\ginitable.c(168)
soup_socket_setup_ssl 行 1392                     subprojects\libsoup\libsoup\soup-socket.c(1392)
soup_socket_handshake_async 行 1540               subprojects\libsoup\libsoup\soup-socket.c(1540)
socket_connect_complete 行 380                    subprojects\libsoup\libsoup\soup-connection.c(380)
async_connected 行 941                            subprojects\libsoup\libsoup\soup-socket.c(941)
g_socket_client_async_connect_complete 行 1560    subprojects\glib\gio\gsocketclient.c(1560)
try_next_successful_connection 行 1733            subprojects\glib\gio\gsocketclient.c(1733)
try_next_connection_or_finish 行 1801             subprojects\glib\gio\gsocketclient.c(1801)
g_socket_client_connected_callback 行 1871        subprojects\glib\gio\gsocketclient.c(1871)
g_socket_connection_connect_callback 行 241       subprojects\glib\gio\gsocketconnection.c(241)
socket_source_dispatch 行 4025                    subprojects\glib\gio\gsocket.c(4025)
g_main_loop_run 行 4373                           subprojects\glib\glib\gmain.c(4373)
thread_func 行 1067                               subprojects\gst-plugins-good\ext\soup\gstsouphttpsrc.c(1067)

Gstreamer使用openssl连接的流程如下:

tls/dtls connection-> connection base->connection openssl->ssl_lib->...->x509...

测试URL:

https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_cropped_multilingual.webm

遇到的问题如下:

  1. TLS/SSL support not available


[souphttpsrc][source] Running request for method: GET
[souphttpsrc][source] got headers
[souphttpsrc][source] error: Secure connection setup failed.
[souphttpsrc][source] error: 1; install glib-networking (6), URL: https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_cropped_multilingual.webm, Redirect to: (NULL)
[souphttpsrc][source] Sending message failed: TLS support is not available

解决方法:

添加libgioopenssl.so库并


export GIO_MODULE_DIR=${GST_LIB_INSTALL_DIR}/lib/gio/modules
  1. Secure connection setup failed,Unacceptable TLS certificate


[souphttpsrc][source] Running request for method: GET
[souphttpsrc][source] got headers
[souphttpsrc][source] error: Secure connection setup failed.
[souphttpsrc][source] error: Unacceptable TLS certificate (6), URL: https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_cropped_multilingual.webm, Redirect to: (NULL)
[GST_ERROR_SYSTEM][source] posting message: Secure connection setup failed.

解决方法如下:

增加属性"ssl-strict"配置为FALSE;这个变量的主要影响,是在accept_or_reject_peer_certificate认证错误的时候,发送消息,让cb函数来处理这个结果,目前默认返回TRUE,也就是接受,关于这点,也是值得讨论的。发送消息的代码见gtlsconnection.c文档


gboolean
g_tls_connection_emit_accept_certificate (GTlsConnection       *conn,
                      GTlsCertificate      *peer_cert,
                      GTlsCertificateFlags  errors)
{
  gboolean accept = FALSE;

  g_signal_emit (conn, signals[ACCEPT_CERTIFICATE], 0,
         peer_cert, errors, &accept);
  return accept;
}

gstsouphttpsrc将"ssl-strict"配置给soup-session流程如下:


soup_session_set_property 行 695      subprojects\libsoup\libsoup\soup-session.c(695)
object_set_property 行     1571       subprojects\glib\gobject\gobject.c(1571)
g_object_set_valist 行 2465           subprojects\glib\gobject\gobject.c(2465)
g_object_set 行 2634                  subprojects\glib\gobject\gobject.c(2634)
thread_func 行 1019                   subprojects\gst-plugins-good\ext\soup\gstsouphttpsrc.c(1019)

soup-session将"ssl-strict"配置给soup-socket流程如下:


soup_socket_set_property 行 333            subprojects\libsoup\libsoup\soup-socket.c(333)
object_set_property 行    1571             subprojects\glib\gobject\gobject.c(1571)
g_object_new_internal 行 1993              subprojects\glib\gobject\gobject.c(1993)
g_object_new_valist 行 2282                subprojects\glib\gobject\gobject.c(2282)
soup_socket_new 行 848                     subprojects\libsoup\libsoup\soup-socket.c(848)
soup_connection_connect_async 行 414       subprojects\libsoup\libsoup\soup-connection.c(414)
get_connection 行 1957                     subprojects\libsoup\libsoup\soup-session.c(1957)
soup_session_process_queue_item 行 1982    subprojects\libsoup\libsoup\soup-session.c(1982)
async_run_queue 行 2075                    subprojects\libsoup\libsoup\soup-session.c(2075)
idle_run_queue 行 2115                     subprojects\libsoup\libsoup\soup-session.c(2115)

消息的挂接和处理函数见soup-socket.c如下代码:


static gboolean
soup_socket_setup_ssl (SoupSocket    *sock,
               const char    *ssl_host,
               GCancellable  *cancellable,
               GError       **error)
{
……
    priv->ssl = TRUE;

    if (!priv->is_server) {
        GTlsClientConnection *conn;
        GSocketConnectable *identity;

        identity = g_network_address_new (ssl_host, 0);
        conn = g_initable_new (g_tls_backend_get_client_connection_type (backend),
                       cancellable, error,
                       "base-io-stream", priv->conn,
                       "server-identity", identity,
                       "database", priv->ssl_creds,
                       "require-close-notify", FALSE,
                       "use-ssl3", priv->ssl_fallback,
                       NULL);
……
        priv->conn = G_IO_STREAM (conn);

        if (!priv->ssl_strict) {
            g_signal_connect (conn, "accept-certificate",
                      G_CALLBACK (soup_socket_accept_certificate),
                      sock);
        }
    } else {
……
        priv->conn = G_IO_STREAM (conn);
    }
……
    return TRUE;
}

static gboolean
soup_socket_accept_certificate (GTlsConnection *conn, GTlsCertificate *cert,
                GTlsCertificateFlags errors, gpointer sock)
{
    return TRUE;
}

dash/hls 的https播放过程中,由于dash/hls 片段的切换,gstsouphttpsrc可能会多次被创建,因此,每一次创建都需要对这个source设置属性。不建议将属性修改成默认参数FALSE,选择权交给用户吧,安全无小事。注意复杂环境下可能出现的多个同名库的问题,需要用readelf -d或者objdump -x来查看库的依赖问题,同时用如下方法来调试Makefile,查看Makefile中的所有变量,以便链接到正确的库上。


test:
    $(foreach var,$(.VARIABLES),$(info $(var) = $($(var))))

老版本的stadaptivedemux,需要在gst_adaptive_demux_stream_update_source里面创建uri_handler的时候,配置ssl-strict,由source去配置soup-session,同时,由于在GstUriDownloader里面也创建了新的source,GstUriDownloader及其priv创建于demux初始化的时候,所以,可以在GstUriDownloader的priv里面增加一个ssl_strict字段,当配置demux的时候,顺便就配置了这个ssl_strict字段,创建source的时候,参考这个ssl_strict字段即可,如下:


    if (!demux->ssl_strict &&
      g_strstr_len(uri, -1, "https://")) {
      g_object_set(uri_handler, "ssl-strict", FALSE, NULL);
    }
 uri_handler = gst_element_make_from_uri (GST_URI_SRC, uri, NULL, NULL);
    if (uri_handler == NULL) {
      GST_ELEMENT_ERROR (demux, CORE, MISSING_PLUGIN,
          ("Missing plugin to handle URI: '%s'", uri), (NULL));
      gst_object_unref (queue);
      return FALSE;
    }
    if (!demux->ssl_strict &&
      g_strstr_len(uri, -1, "https://")) {
      g_object_set(uri_handler, "ssl-strict", FALSE, NULL);
    }
case PROP_STRICT_SSL:
  demux->ssl_strict = g_value_get_boolean (value);
  gst_uri_downloader_set_ssl_strict(demux->downloader, demux->ssl_strict);


void
gst_uri_downloader_set_ssl_strict (
    GstUriDownloader * downloader, gboolean ssl_strict)
{
    g_return_if_fail (downloader != NULL);
    g_return_if_fail (downloader->priv != NULL);

    downloader->priv->ssl_strict = ssl_strict;
}

if (!downloader->priv->urisrc) {
  GST_DEBUG_OBJECT (downloader, "Creating source element for the URI:%s",
      uri);
  downloader->priv->urisrc =
      gst_element_make_from_uri (GST_URI_SRC, uri, NULL, NULL);
  if (downloader->priv->urisrc) {
    /* gst_element_make_from_uri returns a floating reference
     * and we are not going to transfer the ownership, so we
     * should take it.
     */
    gst_object_ref_sink (downloader->priv->urisrc);
    g_object_set(downloader->priv->urisrc,
      "ssl-strict", downloader->priv->ssl_strict, NULL);
  }
}

    而新版本的adaptivedemux2不行,需要配置GstAdaptiveDemux的DownloadHelper的session,这个session,就是soup-session,在这里面手动配置。


void downloadhelper_set_ssl_strict (DownloadHelper * dh, gboolean ssl_strict)
{
    if (dh && dh->session) {
        g_object_set(dh->session, "ssl-strict", FALSE, NULL);
    }
}
  1. 高安组件使用到libcurl库下载https的数据,关于libcurl使用arm交叉编译的问题。

  • 错误A:不能找到ssl,crypto库,报错如下:


/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: warning: libpsl.so.5, needed by ../lib/.libs/libcurl.so, not found (try using -rpath or -rpath-link)
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: warning: libssl.so, needed by ../lib/.libs/libcurl.so, not found (try using -rpath or -rpath-link)
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: warning: libcrypto.so, needed by ../lib/.libs/libcurl.so, not found (try using -rpath or -rpath-link)
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: ../lib/.libs/libcurl.so: undefined reference to `EVP_PKEY_copy_parameters'
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: ../lib/.libs/libcurl.so: undefined reference to `X509_LOOKUP_file'
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: ../lib/.libs/libcurl.so: undefined reference to `ASN1_TIME_print'
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: ../lib/.libs/libcurl.so: undefined reference to `TLS_client_method

打印出错时的链接参数如下:


libtool: link: /usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc -march=armv7-a -mtune=cortex-a7 -mabi=aapcs-linux -mfloat-abi=hard -mfpu=neon-vfpv4 -mthumb-interwork -marm -rdynamic -funwind-tables -fno-omit-frame-pointer -fno-optimize-sibling-calls -mapcs-frame -fstack-protector-strong -Wl,--build-id -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -g -O2 -Werror=incompatible-pointer-types -Werror=uninitialized -Werror-implicit-function-declaration -isystem /xxx//output//arm//include -isystem /xxx/output//arm//include -fPIC -rdynamic -funwind-tables -fomit-frame-pointer -fno-common -Werror-implicit-function-declaration -Wno-system-headers -o .libs/curl slist_wc.o tool_binmode.o tool_bname.o tool_cb_dbg.o tool_cb_hdr.o tool_cb_prg.o tool_cb_rea.o tool_cb_see.o tool_cb_wrt.o tool_cfgable.o tool_dirhie.o tool_doswin.o tool_easysrc.o tool_filetime.o tool_findfile.o tool_formparse.o tool_getparam.o tool_getpass.o tool_help.o tool_helpers.o tool_hugehelp.o tool_libinfo.o tool_listhelp.o tool_main.o tool_msgs.o tool_operate.o tool_operhlp.o tool_paramhlp.o tool_parsecfg.o tool_progress.o tool_strdup.o tool_setopt.o tool_sleep.o tool_urlglob.o tool_util.o tool_vms.o tool_writeout.o tool_writeout_json.o tool_xattr.o ../lib/strtoofft.o ../lib/timediff.o ../lib/nonblock.o ../lib/warnless.o ../lib/curl_multibyte.o ../lib/version_win32.o ../lib/dynbuf.o  -L/xxx//output//arm//lib -L/xxx//output/arm/lib ../lib/.libs/libcurl.so -lz -pthread -Wl,-rpath -Wl,/xxx/output//arm/lib

-Wl已经指定了rpath,故不存在不能找到库A依赖B,B依赖C的情况,并且libpsl.so,libssl.so,libcrypto.so都已经存在于lib下面。仔细阅读这个link参数,发现未加入-l参数,于是在编译配置的Makefile中加入LIBS参数LIBS=-lssl -lcrypto -lpsl解决问题。

如下:


LIBS=-lssl -lcrypto -lpsl
CPPFLAGS = -I$(SOURCE_INC_DIR)
LDFLAGS = -L$(SOURCE_PREFIX_DIR)/lib
CFLAGS += $(CPPFLAGS) $(LIBS) -fPIC -rdynamic -funwind-tables -fomit-frame-pointer -fno-common
PKG_CONFIG_PATH = $(SOURCE_PREFIX_DIR)/lib/pkgconfig
PKG_CONFIG_LIBDIR = $(PKG_CONFIG_PATH)
CXXFLAGS = $(CFLAGS)
export CPPFLAGS CFLAGS LDFLAGS CXXFLAGS LIBS PKG_CONFIG_PATH PKG_CONFIG_LIBDIR
CONFIGURE_ARGS = CC="$(CC)" \
  --with-openssl=$(SOURCE_PREFIX_DIR) \
  --disable-stripping \
  --without-gnutls \
  --host="$(HOST)" \
  --build="$(MAKE_HOST)"\
  --enable-shared \
  --enable-static \
  --prefix=$(SOURCE_PREFIX_DIR)  
all:
@echo "generate makefile for $(SOURCE_BUILD_DIR)/$(CODE_PATH)";
mkdir -p $(SOURCE_BUILD_DIR)/$(CODE_PATH);
cd $(SOURCE_BUILD_DIR)/$(CODE_PATH); $(SOURCE_DIR)/$(CODE_PATH)/configure $(CONFIGURE_ARGS);
touch $(SOURCE_BUILD_DIR)/$(CODE_PATH)/makefile-done;
cd $(SOURCE_BUILD_DIR)/$(CODE_PATH); make -j$(j) V=1; make install
$(AT)$(MAKE) -f $(CURRENT_MAKEFILES) -r install
install:
uninstall:
clean:
-rm -rf ${SOURCE_PREFIX_DIR}/build/libcurl
distclean:

以上配置用于描述解决问题的方案,不代表整个方案直接粘贴复制可用,部分变量需要配置,另外,libcurl编译过程中,一定要注意是否有生成build目录,调试脚本时,最好将这个目录每次都删除,以免部分参数没有配置进去导致一些奇怪的问题。

  • 错误B: configure: error: C compiler cannot create executables具体如下:


configure: WARNING: Continuing even with errors mentioned immediately above this line.
checking for a BSD-compatible install... /usr/bin/install -c
checking for arm-linux-gnueabihf-gcc... /usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc -march=armv7-a -mtune=cortex-a7 -mabi=aapcs-linux -mfloat-abi=hard -mfpu=neon-vfpv4 -mthumb-interwork -marm -rdynamic -funwind-tables -fno-omit-frame-pointer -fno-optimize-sibling-calls -mapcs-frame -fstack-protector-strong  -Wl,--build-id -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
checking whether the C compiler works... no
configure: error: in `/XXX/output/arm/build/libcurl/curl-7.88.1':
configure: error: C compiler cannot create executables
See `config.log' for more details

查看build\libcurl\curl-7.88.1\config.log文件,找到如下错误:


configure:4906: checking whether the C compiler works
configure:4928: /usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc -march=armv7-a -mtune=cortex-a7 -mabi=aapcs-linux -mfloat-abi=hard -mfpu=neon-vfpv4 -mthumb-interwork -marm -rdynamic -funwind-tables -fno-omit-frame-pointer -fno-optimize-sibling-calls -mapcs-frame -fstack-protector-strong  -Wl,--build-id -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -g -O2 -Werror=incompatible-pointer-types -Werror=uninitialized -Werror-implicit-function-declaration -I/xxx/output//arm//include -I/xxx/output//arm//include -lssl -lcrypto -lpsl -fPIC -rdynamic -funwind-tables -fomit-frame-pointer -fno-common -I/xxx/output//arm//include -L/xxx/output//arm//lib conftest.c -lssl -lcrypto -lpsl >&5
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lssl
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lcrypto
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lpsl
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lssl
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lcrypto
/usr/local/linaro/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/8.3.0/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lpsl
collect2: error: ld returned 1 exit status
configure:4932: $? = 1
configure:4972: result: no

就是要先编译openssl这些东西,编译后解决。

  • 错误C:error: OpenSSL libs and/or directories were not found where specified!,具体情况如下:


checking whether to enable Windows native SSL/TLS... no
checking whether to enable Secure Transport... no
checking whether to enable Amiga native SSL/TLS (AmiSSL v5)... no
checking for HMAC_Update in -lcrypto... yes
checking for SSL_connect in -lssl... yes
checking for openssl/x509.h... no
checking for openssl/rsa.h... no
checking for openssl/crypto.h... no
checking for openssl/pem.h... no
checking for openssl/ssl.h... no
checking for openssl/err.h... no
checking for x509.h... no
checking for rsa.h... no
checking for crypto.h... no
checking for pem.h... no
checking for ssl.h... no
checking for err.h... yes
configure: error: OpenSSL libs and/or directories were not found where specified!

就是找不到openssl的那一系列头文件,gstreamer编译的openssl需要在openssl的meson.build文件中加入安装头文件的命令:


openssl_installdir = join_paths(get_option('prefix'), 'include')
openssl_public_headers += files([
  'include/openssl/aes.h',
  ......
])
install_headers(openssl_public_headers,
  install_dir: join_paths(openssl_installdir, 'openssl'))

另外openssl也最好生成pkg文件,加入如下两句:


pkg = import('pkgconfig')
pkg.generate(libcrypto_lib,
  libraries : libcrypto_dep,
  name : 'libcrypto',
  description : 'A Crypto library')
pkg.generate(libssl_lib,
  libraries : libssl_dep,
  name : 'libssl',
  description : 'A SSL library')

这儿有篇文章,介绍了curl的参数设置:PHP: curl_setopt - Manual

  • 错误D:SSL routines:ssl3_read_n:unexpected eof while


[ERROR:core/test/http_socket.cpp(446):Read] SSL_read returned 0, LibSSL Error = 1
[ERROR:core/test/http_socket.cpp(72):LogBoringSslError]   BoringSSL Error: 0077FFB6:error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading:../../../../gstreamer/gstreamer/subprojects/openssl-3.0.2/ssl/record/rec_layer_s3.c:309:

这是由于期望获取的数据长度大于实际数据长度造成的,需要做如下配置:


ctx = SSL_CTX_new(c->listen ? SSLv23_server_method() : SSLv23_client_method());
SSL_CTX_set_options(ctx, SSL_OP_IGNORE_UNEXPECTED_EOF);

注意:

        在Linux上,确定需要soup-2.4-1并且准备好soup-2.4-1之后,将其打包到文件系统中,gstsouploader.c中的gst_soup_load_library可能并不能成功加载soup-2.4-1,原因并不是soup-2.4-1的依赖没有打包,是soup-2.4-1依赖的依赖没有打包到文件系统中去,至于是哪个依赖,gstreamer加载的时候并不会报错,因此很难定位到需要的库,这儿介绍一下快捷定位的方法。

  1. APP测试文件中调用soup-2.4-1中的某个API
  2. 在APP测试Makefile中动态库依赖加上soup-4-1,如-l soup-4-1,这个时候,系统加载soup-4-1不成功时会提示缺失的动态库名称。
  3. 打印缺失的动态库到文件系统中即可。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值