Files @ 9206016be13b
Branch filter:

Location: CSY/reowolf/src/runtime2/tests/internet.rs - annotation

9206016be13b 6.2 KiB application/rls-services+xml Show Source Show as Raw Download as Raw
Max Henger
Merge branch 'feat-tcp-listener' into 'master'

feat: tcp listener

See merge request nl-cwi-csy/reowolf!9
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
2811715674ea
use super::*;

// silly test to make sure that the PDL will never be an issue when doing TCP
// stuff with the actual components
#[test]
fn test_stdlib_file() {
    compile_and_create_component("
    import std.internet as inet;

    comp fake_listener_once(out<inet::TcpConnection> tx) {
        channel cmd_tx -> cmd_rx;
        channel data_tx -> data_rx;
        new fake_socket(cmd_rx, data_tx);
        sync put(tx, inet::TcpConnection{
            tx: cmd_tx,
            rx: data_rx,
        });
    }

    comp fake_socket(in<inet::ClientCmd> cmds, out<u8[]> tx) {
        auto to_send = {};

        auto shutdown = false;
        while (!shutdown) {
            auto keep_going = true;
            sync {
                while (keep_going) {
                    auto cmd = get(cmds);
                    if (let inet::ClientCmd::Send(data) = cmd) {
                        to_send = data;
                        keep_going = false;
                    } else if (let inet::ClientCmd::Receive = cmd) {
                        put(tx, to_send);
                    } else if (let inet::ClientCmd::Finish = cmd) {
                        keep_going = false;
                    } else if (let inet::ClientCmd::Shutdown = cmd) {
                        keep_going = false;
                        shutdown = true;
                    }
                }
            }
        }
    }

    comp fake_client(inet::TcpConnection conn) {
        sync put(conn.tx, inet::ClientCmd::Send({1, 3, 3, 7}));
        sync {
            put(conn.tx, inet::ClientCmd::Receive);
            auto val = get(conn.rx);
            while (val[0] != 1 || val[1] != 3 || val[2] != 3 || val[3] != 7) {
                print(\"this is going very wrong\");
            }
            put(conn.tx, inet::ClientCmd::Finish);
        }
        sync put(conn.tx, inet::ClientCmd::Shutdown);
    }

    comp constructor() {
        channel conn_tx -> conn_rx;
        new fake_listener_once(conn_tx);

        // Same crap as before:
        channel cmd_tx -> unused_cmd_rx;
        channel unused_data_tx -> data_rx;
        auto connection = inet::TcpConnection{ tx: cmd_tx, rx: data_rx };

        sync {
            connection = get(conn_rx);
        }

        new fake_client(connection);
    }
    ", "constructor", no_args());
}

#[test]
fn test_tcp_listener_and_client() {
    compile_and_create_component("
    import std.internet::*;

    func listen_port() -> u16 {
        return 2392;
    }

    comp server(u32 num_connections, in<()> shutdown) {
        // Start tcp listener
        channel listen_cmd_tx -> listen_cmd_rx;
        channel listen_conn_tx -> listen_conn_rx;
        new tcp_listener({}, listen_port(), listen_cmd_rx, listen_conn_tx);

        // Fake channels such that we can create a dummy connection variable
        channel client_cmd_tx -> unused_client_cmd_rx;
        channel unused_client_data_tx -> client_data_rx;
        auto new_connection = TcpConnection{
            tx: client_cmd_tx,
            rx: client_data_rx,
        };

        auto connection_counter = 0;
        while (connection_counter < num_connections) {
            // Wait until we get a connection
            print(\"server: waiting for an accepted connection\");
            sync {
                put(listen_cmd_tx, ListenerCmd::Accept);
                new_connection = get(listen_conn_rx);
            }

            // We have a new connection, spawn an 'echoer' for it
            print(\"server: spawning an echo'ing component\");
            new echo_machine(new_connection);
            connection_counter += 1;
        }

        // Shut down the listener
        print(\"server: shutting down listener\");
        sync auto v = get(shutdown);
        sync put(listen_cmd_tx, ListenerCmd::Shutdown);
    }

    // Waits for a single TCP byte (to simplify potentially having to
    // concatenate requests) and echos it
    comp echo_machine(TcpConnection conn) {
        auto data_to_echo = {};

        // Wait for a message
        sync {
            print(\"echo: receiving data\");
            put(conn.tx, ClientCmd::Receive);
            data_to_echo = get(conn.rx);
            put(conn.tx, ClientCmd::Finish);
        }

        // Echo the message
        print(\"echo: sending back data\");
        sync put(conn.tx, ClientCmd::Send(data_to_echo));

        // Ask the tcp connection to shut down
        print(\"echo: shutting down\");
        sync put(conn.tx, ClientCmd::Shutdown);
    }

    comp echo_requester(u8 byte_to_send, out<()> done) {
        channel cmd_tx -> cmd_rx;
        channel data_tx -> data_rx;
        new tcp_client({127, 0, 0, 1}, listen_port(), cmd_rx, data_tx);

        // Send the message
        print(\"requester: sending bytes\");
        sync put(cmd_tx, ClientCmd::Send({ byte_to_send }));

        // Receive the echo'd byte
        auto received_byte = byte_to_send + 1;
        sync {
            print(\"requester: receiving echo response\");
            put(cmd_tx, ClientCmd::Receive);
            received_byte = get(data_rx)[0];
            put(cmd_tx, ClientCmd::Finish);
        }

        // Silly check, as always
        while (byte_to_send != received_byte) {
            print(\"requester: Oh no! The echo is an otherworldly distorter\");
        }

        // Shut down the TCP connection
        print(\"requester: shutting down TCP component\");
        sync put(cmd_tx, ClientCmd::Shutdown);
        sync put(done, ());
    }

    comp constructor() {
        auto num_connections = 1;
        channel shutdown_listener_tx -> shutdown_listener_rx;
        new server(num_connections, shutdown_listener_rx);

        auto connection_index = 0;
        auto all_done = {};
        while (connection_index < num_connections) {
            channel done_tx -> done_rx;
            new echo_requester(cast(connection_index), done_tx);
            connection_index += 1;
            all_done @= {done_rx};
        }

        auto counter = 0;
        while (counter < length(all_done)) {
            print(\"constructor: waiting for requester to exit\");
            sync auto v = get(all_done[counter]);
            counter += 1;
        }

        print(\"constructor: instructing listener to exit\");
        sync put(shutdown_listener_tx, ());
    }
    ", "constructor", no_args());
}