I'm trying to use a TCP Socket in an iOS Kotlin/Native common module.
According Apple's documentation, to open a nw_connection_t
, you simply need to:
val connection =
nw_parameters_create_secure_tcp(
NW_PARAMETERS_DISABLE_PROTOCOL, // No TLS
NW_PARAMETERS_DEFAULT_CONFIGURATION // Default TCP config
)
However, when I run this module in an iOS Application, I get the following error:
_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
...
The parameters.h
header in Apple's Network.framework contains:
#define NW_PARAMETERS_DISABLE_PROTOCOL (_nw_parameters_configure_protocol_disable)
...so of course _nw_parameters_configure_protocol_disable
is called directly.
Any idea of what I'm doing wrong?
So, it turns out that neither
NW_PARAMETERS_DISABLE_PROTOCOL
norNW_PARAMETERS_DEFAULT_CONFIGURATION
are meant to be invoked. Even though they are of block type^(nw_protocol_options_t)
, thenw_parameters_create_secure_tcp
function uses their pointer adresses as special markers and never actually invokes them.This is a problem because the Kotlin/Native ObjC-interop layer:
NW_PARAMETERS_DISABLE_PROTOCOL
andNW_PARAMETERS_DEFAULT_CONFIGURATION
blocks into Kotlin lambdas.As a result, the actual pointer address of these special blocks is lost, the blocks are called (which they should not), and the failure occurs.
There is no way to address this problem in Kotlin, as the Kotlin version of
nw_parameters_create_secure_tcp
requests lambda parameters (and not pointers).A very simple workaround is to create our own layer of interoperability using our own C-interop def file:
This creates an Objective-C
nw_k_parameters_create_secure_tcp
function (note thenw_k_
prefix) that directly calls the originalnw_parameters_create_secure_tcp
with the correct parameters, without Kotlin block-to-lambda-to-block layer, which can be correctly called from Kotlin.