Skip to content

Commit

Permalink
KTOR-6960 Add UnixDomainSocket support for Native targets (#4024)
Browse files Browse the repository at this point in the history
* KTOR-6960 Add un.h/afunix.h cinterop definition files

* KTOR-6960 Implement pack/unpack sockaddr_un functionality for androidNative/iOS/tvOS/watchOS/windows

* KTOR-6960 use linux/un.h for cinterop instead of sys/un.h
  • Loading branch information
05nelsonm authored Jan 8, 2025
1 parent 177b3a4 commit 1ade60a
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 15 deletions.
3 changes: 3 additions & 0 deletions ktor-network/androidNative/interop/un.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package = io.ktor.network.interop
headers = linux/un.h
headerFilter = linux/un.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ internal actual fun ktor_inet_ntop(
size: UInt
): CPointer<ByteVar>? = inet_ntop(family, src, dst, size.convert())

@OptIn(ExperimentalForeignApi::class)
internal actual fun <T> unpack_sockaddr_un(
sockaddr: sockaddr,
block: (family: UShort, path: String) -> T
): T {
error("Address ${sockaddr.sa_family} is not supported on Android Native")
val address = sockaddr.ptr.reinterpret<sockaddr_un>().pointed
return block(address.sun_family.convert(), address.sun_path.toKString())
}

@OptIn(ExperimentalForeignApi::class)
Expand All @@ -31,5 +33,10 @@ internal actual fun pack_sockaddr_un(
path: String,
block: (address: CPointer<sockaddr>, size: UInt) -> Unit
) {
error("Address $family is not supported on Android Native")
cValue<sockaddr_un> {
strcpy(sun_path, path)
sun_family = family.convert()

block(ptr.reinterpret(), sizeOf<sockaddr_un>().convert())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

package io.ktor.network.sockets.tests

internal actual fun Any.supportsUnixDomainSockets(): Boolean = false
internal actual fun Any.supportsUnixDomainSockets(): Boolean = true
9 changes: 9 additions & 0 deletions ktor-network/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ kotlin {
createCInterop("network", nixTargets()) {
definitionFile = projectDir.resolve("nix/interop/network.def")
}
createCInterop("un", androidNativeTargets()) {
definitionFile = projectDir.resolve("androidNative/interop/un.def")
}
createCInterop("un", iosTargets() + tvosTargets() + watchosTargets()) {
definitionFile = projectDir.resolve("darwin/interop/un.def")
}
createCInterop("afunix", windowsTargets()) {
definitionFile = projectDir.resolve("windows/interop/afunix.def")
}

sourceSets {
jvmAndPosixMain {
Expand Down
3 changes: 3 additions & 0 deletions ktor-network/darwin/interop/un.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package = io.ktor.network.interop
headers = sys/un.h
headerFilter = sys/un.h
12 changes: 10 additions & 2 deletions ktor-network/ios/src/io/ktor/network/util/SocketUtilsIos.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@

package io.ktor.network.util

import io.ktor.network.interop.*
import kotlinx.cinterop.*
import platform.posix.*

@OptIn(ExperimentalForeignApi::class)
internal actual fun <T> unpack_sockaddr_un(
sockaddr: sockaddr,
block: (family: UShort, path: String) -> T
): T {
error("Address ${sockaddr.sa_family} is not supported on ios")
val address = sockaddr.ptr.reinterpret<sockaddr_un>().pointed
return block(address.sun_family.convert(), address.sun_path.toKString())
}

@OptIn(ExperimentalForeignApi::class)
Expand All @@ -22,5 +25,10 @@ internal actual fun pack_sockaddr_un(
path: String,
block: (address: CPointer<sockaddr>, size: socklen_t) -> Unit
) {
error("Address $family is not supported on ios")
cValue<sockaddr_un> {
strcpy(sun_path, path)
sun_family = family.convert()

block(ptr.reinterpret(), sizeOf<sockaddr_un>().convert())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

package io.ktor.network.sockets.tests

internal actual fun Any.supportsUnixDomainSockets(): Boolean = false
internal actual fun Any.supportsUnixDomainSockets(): Boolean = true
12 changes: 10 additions & 2 deletions ktor-network/tvos/src/io/ktor/network/util/SocketUtilsTvos.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@

package io.ktor.network.util

import io.ktor.network.interop.*
import kotlinx.cinterop.*
import platform.posix.*

@OptIn(ExperimentalForeignApi::class)
internal actual fun <T> unpack_sockaddr_un(
sockaddr: sockaddr,
block: (family: UShort, path: String) -> T
): T {
error("Address ${sockaddr.sa_family} is not supported on tvos")
val address = sockaddr.ptr.reinterpret<sockaddr_un>().pointed
return block(address.sun_family.convert(), address.sun_path.toKString())
}

@OptIn(ExperimentalForeignApi::class)
Expand All @@ -22,5 +25,10 @@ internal actual fun pack_sockaddr_un(
path: String,
block: (address: CPointer<sockaddr>, size: socklen_t) -> Unit
) {
error("Address $family is not supported on tvos")
cValue<sockaddr_un> {
strcpy(sun_path, path)
sun_family = family.convert()

block(ptr.reinterpret(), sizeOf<sockaddr_un>().convert())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

package io.ktor.network.sockets.tests

internal actual fun Any.supportsUnixDomainSockets(): Boolean = false
internal actual fun Any.supportsUnixDomainSockets(): Boolean = true
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@

package io.ktor.network.util

import io.ktor.network.interop.*
import kotlinx.cinterop.*
import platform.posix.*

@OptIn(ExperimentalForeignApi::class)
internal actual fun <T> unpack_sockaddr_un(
sockaddr: sockaddr,
block: (family: UShort, path: String) -> T
): T {
error("Address ${sockaddr.sa_family} is not supported on watchos")
val address = sockaddr.ptr.reinterpret<sockaddr_un>().pointed
return block(address.sun_family.convert(), address.sun_path.toKString())
}

@OptIn(ExperimentalForeignApi::class)
Expand All @@ -22,5 +25,10 @@ internal actual fun pack_sockaddr_un(
path: String,
block: (address: CPointer<sockaddr>, size: socklen_t) -> Unit
) {
error("Address $family is not supported on watchos")
cValue<sockaddr_un> {
strcpy(sun_path, path)
sun_family = family.convert()

block(ptr.reinterpret(), sizeOf<sockaddr_un>().convert())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

package io.ktor.network.sockets.tests

internal actual fun Any.supportsUnixDomainSockets(): Boolean = false
internal actual fun Any.supportsUnixDomainSockets(): Boolean = true
18 changes: 18 additions & 0 deletions ktor-network/windows/interop/afunix.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package = io.ktor.network.interop
---
#ifndef _WIN32
error Only Win32 targets are supported!
#endif // _WIN32

#ifdef KTOR_HAVE_AF_UNIX_H
#include <afunix.h>
#else
#include <winsock2.h>

#define UNIX_PATH_MAX 108

struct sockaddr_un {
ADDRESS_FAMILY sun_family;
char sun_path[UNIX_PATH_MAX];
} SOCKADDR_UN, *PSOCKADDR_UN;
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

package io.ktor.network.util

import io.ktor.network.interop.*
import kotlinx.cinterop.*
import platform.posix.*
import platform.posix.AF_INET
Expand Down Expand Up @@ -39,6 +40,14 @@ private val initSocketsIfNeeded by lazy {
}
}

internal val isAFUnixSupported by lazy {
initSocketsIfNeeded
val s = socket(platform.posix.AF_UNIX, SOCK_STREAM, 0)
if (s == INVALID_SOCKET) return@lazy false
platform.posix.closesocket(s)
true
}

internal actual fun initSocketsIfNeeded() {
initSocketsIfNeeded
}
Expand Down Expand Up @@ -115,11 +124,15 @@ internal actual fun ktor_inet_ntop(
size: UInt
): CPointer<ByteVar>? = inet_ntop(family, src, dst, size.convert())

@OptIn(ExperimentalForeignApi::class)
internal actual fun <T> unpack_sockaddr_un(
sockaddr: sockaddr,
block: (family: UShort, path: String) -> T
): T {
error("Address ${sockaddr.sa_family} is not supported on Windows")
check(isAFUnixSupported) { "Address ${sockaddr.sa_family} is not supported on Windows" }

val address = sockaddr.ptr.reinterpret<sockaddr_un>().pointed
return block(address.sun_family.convert(), address.sun_path.toKString())
}

@OptIn(ExperimentalForeignApi::class)
Expand All @@ -128,7 +141,14 @@ internal actual fun pack_sockaddr_un(
path: String,
block: (address: CPointer<sockaddr>, size: UInt) -> Unit
) {
error("Address $family is not supported on Windows")
check(isAFUnixSupported) { "Address $family is not supported on Windows" }

cValue<sockaddr_un> {
strcpy(sun_path, path)
sun_family = family.convert()

block(ptr.reinterpret(), sizeOf<sockaddr_un>().convert())
}
}

internal actual val reusePortFlag: Int? = null // Unsupported on Windows
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@

package io.ktor.network.sockets.tests

internal actual fun Any.supportsUnixDomainSockets(): Boolean = false
import io.ktor.network.util.*

internal actual fun Any.supportsUnixDomainSockets(): Boolean = isAFUnixSupported

0 comments on commit 1ade60a

Please sign in to comment.