June 20, 2018

TCP programming in Kyu

This is still buggy -- client connections are OK, but servers that listen for connections have issues.

If you are hoping for a socket API, you are out of luck. But honestly, a callback driven API is a lot cleaner anyway, and that is the ultimate goal.

The following documents the state of things right now, but this API will definitely be revised.

The current API has the notion of "slots" that are used by the TCP stack to distribute packets. This will certainly be replaced by something else, but that is what we have now.

A key concept is the notion of an active or passive connection. A server is a passive connection - it sets itself up and passively waits for clients to connect. A client is an active connection - it sets up a connection to handle traffic then starts the ball rolling.

Setting up a TCP client

If "TEST_SERVER" is running the classic daytime server on port 13, running the following will yield:
Client recv got 20 JUN 2018 10:49:24 MST
	int port = DAYTIME_PORT;
        int slot;
        char buf[100];
        int n;

        slot = tcp_register ( dots2ip(TEST_SERVER), port, 1 );
        n = tcp_recv ( slot, buf, 100 );
        buf[n] = '\0';
        printf ( "Client recv got %s\n", buf );
        tcp_close ( slot );
The "tcp_register" call gives the IP and port of the target server, and the "1" argument indicates the connection will be active. In the case of the daytime server, nothing is sent -- as soon as a connection is made, it responds with the time of day and closes the connection.

Setting up a TCP server

Here a passive connection is required.
	int lslot;
        int cslot;
        int rv;
        int port = 1234;

        lslot = tcp_register ( 0, port, 0 );
        printf ( "Server listening on port %d (slot %d)\n", port, lslot );

        for ( ;; ) {
            printf ( "Waiting for connection on port %d\n", port );
            rv = tcp_recv ( lslot, (char *) &cslot, 4 );
            if ( rv < 0 ) {
                /* Without this check, once we tie up all slots in
                 * TWAIT, this will yield a runaway loop
                 */
                printf ( "recv on port %d fails - maybe no more slots?\n", port );
                break;
            }
            printf ( "Connection on port %d!! rv= %d, slot= %d\n", port, rv, cslot );
            tcp_send ( cslot, "dog\n", 4 );
            tcp_send ( cslot, "cat\n", 4 );
            tcp_close ( cslot );
        }
        printf ( "Server on port %d exiting !!\n", port );
In the passive case, the "tcp_register" function returns a "slot" that can be used to listen for connections. Once a connection is made, the "tcp_recv" function will return a "slot number" that can be used to handle the connection in the same way that an active client connection would.


Have any comments? Questions? Drop me a line!

Kyu / tom@mmto.org