_nw_parameters_configure_protocol_disable iOS вызывается напрямую

Я пытаюсь использовать сокет TCP в общем модуле iOS Kotlin/Native.

Согласно документации Apple, чтобы открытьnw_connection_t, вам просто необходимо:

val connection = 
    nw_parameters_create_secure_tcp(
        NW_PARAMETERS_DISABLE_PROTOCOL,      // No TLS
        NW_PARAMETERS_DEFAULT_CONFIGURATION  // Default TCP config
    )

Однако когда я запускаю этот модуль в приложении iOS, я получаю следующую ошибку:

_nw_parameters_configure_protocol_disable_block_invoke _nw_parameters_configure_protocol_disable called directly, dumping backtrace:
[x86_64] libnetcore-1880.120.4
    0   libnetwork.dylib                    0x00007fff5118d1f8 __nw_create_backtrace_string + 120
    1   libnetwork.dylib                    0x00007fff5100a898 _nw_parameters_configure_protocol_disable_block_invoke + 120
    2   PhoenixShared                       0x00000001099af1b5 _70686f656e69783a70686f656e69782d736861726564_knbridge41 + 37
    3   PhoenixShared                       0x0000000109972eac kfun:fr.acinq.phoenix.io.BlockFunctionImpl16.invoke#internal + 220
    4   PhoenixShared                       0x0000000109972fbf kfun:fr.acinq.phoenix.io.BlockFunctionImpl16.$<bridge-UNNN>invoke(platform.darwin.NSObject?){}#internal + 95
    5   PhoenixShared                       0x000000010997342b _70686f656e69783a70686f656e69782d736861726564_knbridge47 + 251
    6   libnetwork.dylib                    0x00007fff5100d7b6 nw_parameters_create_secure_tcp + 342
...

В parameters.h заголовок в Apple Network.framework содержит:

#define NW_PARAMETERS_DISABLE_PROTOCOL (_nw_parameters_configure_protocol_disable)

... так что конечно _nw_parameters_configure_protocol_disable вызывается напрямую.

Есть идеи, что я делаю неправильно?

1 ответ

Итак, оказывается, что ни NW_PARAMETERS_DISABLE_PROTOCOL ни NW_PARAMETERS_DEFAULT_CONFIGURATIONпредназначены для вызова. Хотя они блочного типа^(nw_protocol_options_t), то nw_parameters_create_secure_tcp функция использует их адреса указателей как специальные маркеры и никогда не вызывает их.

Это проблема, потому что уровень взаимодействия Kotlin/Native ObjC:

  1. Преобразованный NW_PARAMETERS_DISABLE_PROTOCOL а также NW_PARAMETERS_DEFAULT_CONFIGURATION блоки в лямбды Котлина.
  2. Оборачивает лямбда-выражения, чтобы преобразовать их обратно в блоки ObjC при передаче их в качестве аргументов (как мы можем видеть в строках трассировки стека вопроса с номерами 3 и 4).

В результате фактический адрес указателя этих специальных блоков теряется, блоки вызываются (чего они не должны делать) и происходит сбой.

В Kotlin нет способа решить эту проблему, так как Kotlin версия nw_parameters_create_secure_tcp запрашивает лямбда-параметры (а не указатели).

Очень простой обходной путь - создать наш собственный уровень взаимодействия с использованием нашего собственного файла C-interop def:

package = fr.acinq.phoenix.io.network_framework
language = Objective-C

---

#include <Network/Network.h>

NW_RETURNS_RETAINED nw_parameters_t nw_k_parameters_create_secure_tcp(bool withTls) {
    return nw_parameters_create_secure_tcp(
        withTls ? NW_PARAMETERS_DEFAULT_CONFIGURATION : NW_PARAMETERS_DISABLE_PROTOCOL,
        NW_PARAMETERS_DEFAULT_CONFIGURATION
    );
}

Это создает Objective-C nw_k_parameters_create_secure_tcp функция (обратите внимание на nw_k_ префикс), который напрямую вызывает исходный nw_parameters_create_secure_tcp с правильными параметрами, без уровня Kotlin block-to-lambda-to-block, который можно правильно вызвать из Kotlin.

Другие вопросы по тегам