From 2dde9eda55f27df3f2627a85d6c50a74401fccf8 Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Mon, 23 Oct 2017 14:15:28 +0300 Subject: [PATCH] Fix socket example on POSIX (#966) --- .../interop/gen/jvm/InteropConfiguration.kt | 3 +- .../native/interop/gen/jvm/StubGenerator.kt | 11 +++-- .../kotlin/native/interop/gen/jvm/main.kt | 3 +- klib/src/platform/android/posix.def | 7 ++++ klib/src/platform/ios/posix.def | 7 ++++ klib/src/platform/linux/posix.def | 7 ++++ klib/src/platform/osx/posix.def | 7 ++++ klib/src/platform/windows/posix.def | 17 +++++++- klib/src/platform/windows/windows.def | 3 +- samples/socket/src/main/kotlin/EchoServer.kt | 40 +++++++++++-------- .../jetbrains/kotlin/konan/util/DefFile.kt | 4 ++ 11 files changed, 84 insertions(+), 25 deletions(-) diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/InteropConfiguration.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/InteropConfiguration.kt index 3b1640c8bb3..12f481e2a1a 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/InteropConfiguration.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/InteropConfiguration.kt @@ -26,5 +26,6 @@ class InteropConfiguration( val pkgName: String, val excludedFunctions: Set, val strictEnums: Set, - val nonStrictEnums: Set + val nonStrictEnums: Set, + val noStringConversion: Set ) \ No newline at end of file diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt index 93aa113f4d5..cb26432824d 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt @@ -57,6 +57,10 @@ class StubGenerator( val excludedFunctions: Set get() = configuration.excludedFunctions + val noStringConversion: Set + get() = configuration.noStringConversion + + val platformWStringTypes = setOf("LPCWSTR") /** @@ -305,10 +309,11 @@ class StubGenerator( return false } - fun representCFunctionParameterAsString(type: Type): Boolean { + fun representCFunctionParameterAsString(function: FunctionDecl, type: Type): Boolean { val unwrappedType = type.unwrapTypedefs() return unwrappedType is PointerType && unwrappedType.pointeeIsConst && - unwrappedType.pointeeType.unwrapTypedefs() == CharType + unwrappedType.pointeeType.unwrapTypedefs() == CharType && + !noStringConversion.contains(function.name) } // We take this approach as generic 'const short*' shall not be used as String. @@ -612,7 +617,7 @@ class StubGenerator( val representAsValuesRef = representCFunctionParameterAsValuesRef(parameter.type) - val bridgeArgument = if (representCFunctionParameterAsString(parameter.type)) { + val bridgeArgument = if (representCFunctionParameterAsString(func, parameter.type)) { kotlinParameters.add(parameterName to KotlinTypes.string.makeNullable()) bodyGenerator.pushMemScoped() "$parameterName?.cstr?.getPointer(memScope)" diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt index deee12bdd05..8f9dd4452cd 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt @@ -310,7 +310,8 @@ private fun processLib(args: Map>, pkgName = outKtPkg, excludedFunctions = excludedFunctions, strictEnums = def.config.strictEnums.toSet(), - nonStrictEnums = def.config.nonStrictEnums.toSet() + nonStrictEnums = def.config.nonStrictEnums.toSet(), + noStringConversion = def.config.noStringConversion.toSet() ) val nativeIndex = buildNativeIndex(library) diff --git a/klib/src/platform/android/posix.def b/klib/src/platform/android/posix.def index 4df526590ce..94486be0bf6 100644 --- a/klib/src/platform/android/posix.def +++ b/klib/src/platform/android/posix.def @@ -26,4 +26,11 @@ static int posix_errno() { // Wrapper to access h_errno variable. static int posix_h_errno() { return h_errno; +} + +static int init_sockets() { + return 0; +} + +static void deinit_sockets() { } \ No newline at end of file diff --git a/klib/src/platform/ios/posix.def b/klib/src/platform/ios/posix.def index 02ce3801287..d5d157d4c19 100644 --- a/klib/src/platform/ios/posix.def +++ b/klib/src/platform/ios/posix.def @@ -26,3 +26,10 @@ static int posix_errno() { static int posix_h_errno() { return h_errno; } + +static int init_sockets() { + return 0; +} + +static void deinit_sockets() { +} \ No newline at end of file diff --git a/klib/src/platform/linux/posix.def b/klib/src/platform/linux/posix.def index 5e28aefdbbb..c82ab3a0fa3 100644 --- a/klib/src/platform/linux/posix.def +++ b/klib/src/platform/linux/posix.def @@ -62,3 +62,10 @@ static void posix_FD_SET(int bit, fd_set *set) { static int posix_FD_ISSET(int bit, fd_set *set) { return FD_ISSET(bit, set); } + +static int init_sockets() { + return 0; +} + +static void deinit_sockets() { +} \ No newline at end of file diff --git a/klib/src/platform/osx/posix.def b/klib/src/platform/osx/posix.def index ef3f5c31063..29a2ec14bed 100644 --- a/klib/src/platform/osx/posix.def +++ b/klib/src/platform/osx/posix.def @@ -48,3 +48,10 @@ static void posix_FD_SET(int bit, fd_set *set) { static int posix_FD_ISSET(int bit, fd_set *set) { return FD_ISSET(bit, set); } + +static int init_sockets() { + return 0; +} + +static void deinit_sockets() { +} \ No newline at end of file diff --git a/klib/src/platform/windows/posix.def b/klib/src/platform/windows/posix.def index ada704b5bb7..80782fc465f 100644 --- a/klib/src/platform/windows/posix.def +++ b/klib/src/platform/windows/posix.def @@ -1,6 +1,8 @@ package = platform.posix -headers = stdio.h Windef.h Winsock2.h Ws2tcpip.h Ws2def.h io.h math.h -compilerOpts = -DUNICODE -Wno-incompatible-pointer-types -Wno-deprecated-declarations +headers = stdio.h winsock.h io.h math.h +compilerOpts = -DUNICODE -DWINVER=0x0601 -D_WIN32_WINNT=0x0601 -DWINAPI_FAMILY=3 \ + -Wno-incompatible-pointer-types -Wno-deprecated-declarations +noStringConversion = send recv linkerOpts = -lWs2_32 --- @@ -29,3 +31,14 @@ static void posix_FD_SET(int bit, fd_set *set) { static int posix_FD_ISSET(int bit, fd_set *set) { return FD_ISSET(bit, set); } + +static int init_sockets() { + WORD wVersionRequested = MAKEWORD(2, 2); + WSADATA wsaData; + return WSAStartup(wVersionRequested, &wsaData); +} + +static void deinit_sockets() { + WSACleanup(); + return; +} \ No newline at end of file diff --git a/klib/src/platform/windows/windows.def b/klib/src/platform/windows/windows.def index 6639e29c9e6..aada904b597 100644 --- a/klib/src/platform/windows/windows.def +++ b/klib/src/platform/windows/windows.def @@ -1,6 +1,7 @@ package = platform.windows headers = windows.h commctrl.h dwmapi.h shlobj.h shlwapi.h shobjidl.h \ - urlmon.h usp10.h uxtheme.h vfw.h wininet.h + urlmon.h usp10.h uxtheme.h vfw.h wininet.h winsock2.h ws2tcpip.h ws2def.h compilerOpts = -DUNICODE -DWINVER=0x0601 -D_WIN32_WINNT=0x0601 -DWINAPI_FAMILY=3 \ -Wno-incompatible-pointer-types -Wno-deprecated-declarations linkerOpts = -lcomctl32 -lcrypt32 -lshlwapi -lshell32 -limm32 -lusp10 -lwininet +depends = posix diff --git a/samples/socket/src/main/kotlin/EchoServer.kt b/samples/socket/src/main/kotlin/EchoServer.kt index 0afbaf1f765..9bb0dd5616f 100644 --- a/samples/socket/src/main/kotlin/EchoServer.kt +++ b/samples/socket/src/main/kotlin/EchoServer.kt @@ -25,55 +25,61 @@ fun main(args: Array) { val port = args[0].toShort() + // Initialize sockets in platform-dependent way. + init_sockets() + memScoped { - val bufferLength = 100L - val buffer = allocArray(bufferLength) + val buffer = ByteArray(1024) + val prefixBuffer = kotlin.text.toUtf8Array("echo: ", 0, 6) val serverAddr = alloc() val listenFd = socket(AF_INET, SOCK_STREAM, 0) - .ensureUnixCallResult { it >= 0 } + .ensureUnixCallResult("socket") { it >= 0 } with(serverAddr) { memset(this.ptr, 0, sockaddr_in.size) sin_family = AF_INET.narrow() - sin_addr.s_addr = posix_htons(0).toInt() sin_port = posix_htons(port) } bind(listenFd, serverAddr.ptr.reinterpret(), sockaddr_in.size.toInt()) - .ensureUnixCallResult { it == 0 } + .ensureUnixCallResult("bind") { it == 0 } listen(listenFd, 10) - .ensureUnixCallResult { it == 0 } + .ensureUnixCallResult("listen") { it == 0 } val commFd = accept(listenFd, null, null) - .ensureUnixCallResult { it >= 0 } + .ensureUnixCallResult("accept") { it >= 0 } - while (true) { - val length = read(commFd, buffer, bufferLength) - .ensureUnixCallResult { it >= 0 } + buffer.usePinned { pinned -> + while (true) { + val length = recv(commFd, pinned.addressOf(0), buffer.size, 0) + .ensureUnixCallResult("read") { it >= 0 } - if (length.toInt() == 0) { + if (length == 0) { break } - write(commFd, buffer, length) - .ensureUnixCallResult { it >= 0 } + send(commFd, prefixBuffer.refTo(0), prefixBuffer.size, 0) + .ensureUnixCallResult("write") { it >= 0 } + send(commFd, pinned.addressOf(0), length, 0) + .ensureUnixCallResult("write") { it >= 0 } + } } } } -inline fun Int.ensureUnixCallResult(predicate: (Int) -> Boolean): Int { +inline fun Int.ensureUnixCallResult(op: String, predicate: (Int) -> Boolean): Int { if (!predicate(this)) { - throw Error(strerror(posix_errno())!!.toKString()) + throw Error("$op: ${strerror(posix_errno())!!.toKString()}") } return this } -inline fun Long.ensureUnixCallResult(predicate: (Long) -> Boolean): Long { +inline fun Long.ensureUnixCallResult(op: String, predicate: (Long) -> Boolean): Long { if (!predicate(this)) { - throw Error(strerror(posix_errno())!!.toKString()) + throw Error("$op: ${strerror(posix_errno())!!.toKString()}") } return this } diff --git a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/DefFile.kt b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/DefFile.kt index 94c1f070142..8e51ec30cde 100644 --- a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/DefFile.kt +++ b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/DefFile.kt @@ -72,6 +72,10 @@ class DefFile(val file:File?, val config:DefFileConfig, val manifestAddendProper properties.getSpaceSeparated("nonStrictEnums") } + val noStringConversion by lazy { + properties.getSpaceSeparated("noStringConversion") + } + val depends by lazy { properties.getSpaceSeparated("depends") }