June 25, 2023

Kotlin socket programming

Another Kotlin native project.

I have a gadget in my workshop. It is a little ESP8266 wireless listener connected to a big bell. The idea was that someday I would relay a message when the doorbell in the main house got pressed.

It is at address 192.168.0.41 and listens on TCP port 1013. Once you connect to it, you sent the ascii string:

bell
The bell will ring and you will receive the response "OK". An easy way to do this is using netcat. The following will work:
echo "bell" | nc esp_bell 1013
OK

Let's do this with Kotlin native

First, I have to register a bitter complaint. I find various interesting examples online, but hardly anyone ever shows what "import" statements they are using. For all I know they aren't using kotlin native and are relying on Java libraries (and indeed, they often are). So, my request: show an entire piece of working code or go home!

The usual C code to set up and use a socket connection looks like this:

struct sockaddr_in serv_addr;
int sockfd;

sockfd = socket(AF_INET, SOCK_STREAM, 0));
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
stat = onnect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
Translating this to Kotlin is fairly straightforward, but I get stuck when it comes to dealing with the sockaddr_in structure. I iterate using the Kotlin compiler and let the errors suggest to me what types I need to provide. I have gotten this far:
import platform.posix.*
import kotlinx.cinterop.*
import platform.linux.*

val port = 1013
val host = "192.168.0.41"
val timeout = 3000

fun main()
{
    var sock = socket ( AF_INET, SOCK_STREAM, 0 )
    println ( sock )

    val addr = 0
    println ( addr )
    val len = 4

    connect ( sock, addr, len )

    // sock.connect ( InetSocketAddress ( host, port ), timeout )
}
The hints I get from compiler errors are as follows:
kotlinc bell.kt -o bell
bell.kt:19:21: error: type mismatch: inferred type is Int but CValuesRef? was expected
    connect ( sock, addr, len )
                    ^
bell.kt:19:27: error: type mismatch: inferred type is Int but socklen_t /* = UInt */ was expected
    connect ( sock, addr, len )
			  ^
I can use the second error to guide me to the following:
   val len : UInt = 4u
In fact with the "4u" indicating a UInt literal, I could do away with declaring the type and let Kotlin type inference do the right thing. Of course the value "4" is nonsense, but I am just tossing things up and fishing for compiler hints about types at this stage.

But dealing with the type and getting the size of it in bytes is beyond what I know how to deal with at this point.

Do some homework

Give up

Kotlin native is not ready for prime time in this arena. Better documentation on how to interface with the posix C library would be a start.

I installed the IDEA tool on my linux system and had this going in about 5 minutes using the Java Socket calls. I spent most of a day getting nowhere with Kotlin native and sockets.


Have any comments? Questions? Drop me a line!

Adventures in Computing / tom@mmto.org