3. Walk-through

Both the server and message headers are needed, with the support header:

#include <vws/server.h>
#include <vws/message.h>

#include "vwsx.h"

The hook echoes each inbound message. It is declared with the base vws_svr pointer but operates on a vrtql_msg:

static void echo(vws_svr* s, vws_cid_t cid, vrtql_msg* m, void* ctx)
{
    (void)ctx;

    vrtql_msg* reply = vrtql_msg_new();
    reply->format    = m->format;
    vws_buffer_append(reply->content, m->content->data, m->content->size);

    ((vrtql_msg_svr*)s)->send(s, cid, reply, NULL);

    vrtql_msg_free(m);
}

The reply mirrors the request's format — keeping the response in the same wire format, JSON or MessagePack — and copies the request's content buffer into the reply's with vws_buffer_append(). The reply is sent through the message server's own send function, reached by casting the base pointer back to its real type: ((vrtql_msg_svr*)s)->send. This matters because the base vws_svr's send expects a vws_msg, whereas the reply here is a vrtql_msg; the message server's send is the one that accepts it. As with the WebSocket server, send takes ownership of the reply, so the handler frees only the incoming message.

The server is created and the handler installed on its hook:

vrtql_msg_svr* server = vrtql_msg_svr_new(10, 0, 0);

if (server == NULL)
{
    vwsx_die("vrtql_msg_svr_new() failed");
}

server->process = echo;

The handler is assigned to process, the message server's per-message hook — again not the internal on_msg_in dispatcher. The server then runs and stops through the base type, exactly as the other servers do:

vwsx_serve_stop_on_signal((vws_tcp_svr*)server);

vws_tcp_svr_run((vws_tcp_svr*)server, HOST, PORT);

vrtql_msg_svr_free(server);

A vrtql_msg_svr is driven through its base, so the stop-on-signal helper and the blocking vws_tcp_svr_run() both take the server via a (vws_tcp_svr*) cast; vrtql_msg_svr_free() then releases it.