3. Walk-through

The server header and the examples' support header are included:

#include <vws/server.h>

#include "vwsx.h"

The per-message hook echoes each inbound message. It receives the server, the connection id, the incoming vws_msg, and the worker context (unused here):

static void echo(vws_svr* server, vws_cid_t cid, vws_msg* m, void* ctx)
{
    (void)ctx;

    vws_msg* reply = vws_msg_new();
    reply->opcode  = m->opcode;
    vws_buffer_append(reply->data, m->data->data, m->data->size);

    server->send(server, cid, reply, NULL);

    vws_msg_free(m);
}

The reply is a new message that copies the incoming opcode — preserving the message type — and appends the incoming payload with vws_buffer_append(). It is sent through the server's send member, which takes ownership of the reply and frees it; the handler therefore frees only the incoming message, with vws_msg_free().

The server is created in main and the handler is installed on the correct hook:

vws_svr* server = vws_svr_new(10, 0, 0);

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

server->process_ws = echo;

The handler is assigned to process_ws, the hook the framework invokes for each decoded WebSocket message. It must not be assigned to the server's internal on_msg_in dispatcher, which is the code that calls process_ws.

Finally the server is wired to stop on a signal and run:

vwsx_serve_stop_on_signal((vws_tcp_svr*)server);

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

vws_svr_free(server);

A vws_svr embeds a vws_tcp_svr as its first member and is driven through that base: both the stop-on-signal helper and the blocking vws_tcp_svr_run() are passed the server through a (vws_tcp_svr*) cast. Only the base server exposes a stop entry point — vws_tcp_svr_stop() — so a derived server is always stopped through it. When the run returns, vws_svr_free() releases the server.