6 ex__network__ws__limits_8c
gullradriel edited this page 2026-10-09 00:55:18 +02:00

examples/ex_network_ws_limits.c

Functions

Name
int send_hostile_header(NETWORK * peer, uint64_t len)
Send a raw WebSocket frame header naming a payload length of len.
int main(void )
int check_refused(const char * label, uint64_t len)
Drive one hostile length through n_ws_recv and report the outcome.

Defines

Name
WS_LIMITS_PORT
Port the local listener binds for this test.

Functions Documentation

function send_hostile_header

static int send_hostile_header(
    NETWORK * peer,
    uint64_t len
)

Send a raw WebSocket frame header naming a payload length of len.

Parameters:

  • peer Connected socket to write to.
  • len Payload length to declare in the header.

Return: 0 on success, -1 on a short write.

function main

int main(
    void 
)

function check_refused

static int check_refused(
    const char * label,
    uint64_t len
)

Drive one hostile length through n_ws_recv and report the outcome.

Parameters:

  • label Human-readable name of the case.
  • len Payload length the peer declares.

Return: 0 when n_ws_recv refused the frame, 1 when it did not.

Macros Documentation

define WS_LIMITS_PORT

#define WS_LIMITS_PORT "27431"

Port the local listener binds for this test.

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#include "nilorea/n_log.h"
#include "nilorea/n_network.h"
#include "nilorea/n_str.h"

#include <string.h>

#define WS_LIMITS_PORT "27431"

static int send_hostile_header(NETWORK* peer, uint64_t len) {
    unsigned char hdr[10];
    size_t i;
    hdr[0] = 0x81; /* FIN + text */
    hdr[1] = 0x7F; /* 64-bit extended length, not masked */
    for (i = 0; i < 8; i++)
        hdr[2 + i] = (unsigned char)((len >> (56 - 8 * i)) & 0xFF);
    if (send_data(peer, (char*)hdr, (uint32_t)sizeof(hdr)) != (ssize_t)sizeof(hdr))
        return -1;
    return 0;
}

static int check_refused(const char* label, uint64_t len) {
    NETWORK* server = NULL;
    NETWORK* peer = NULL;
    NETWORK* client = NULL;
    N_WS_CONN conn;
    N_WS_MESSAGE msg;
    int rc;
    int failed = 1;

    memset(&conn, 0, sizeof(conn));
    memset(&msg, 0, sizeof(msg));

    if (netw_make_listening(&server, "127.0.0.1", (char*)WS_LIMITS_PORT, 1, NETWORK_IPV4) == FALSE) {
        n_log(LOG_ERR, "FAIL(%s): could not listen on " WS_LIMITS_PORT, label);
        return 1;
    }
    if (netw_connect_to(&client, "127.0.0.1", (char*)WS_LIMITS_PORT, NETWORK_IPV4, 2000) == FALSE) {
        n_log(LOG_ERR, "FAIL(%s): could not connect to the listener", label);
        netw_close(&server);
        return 1;
    }
    peer = netw_accept_from(server);
    if (!peer) {
        n_log(LOG_ERR, "FAIL(%s): listener did not accept", label);
        netw_close(&client);
        netw_close(&server);
        return 1;
    }

    if (send_hostile_header(peer, len) != 0) {
        n_log(LOG_ERR, "FAIL(%s): could not send the frame header", label);
        goto cleanup;
    }

    conn.netw = client;
    conn.connected = 1;
    rc = n_ws_recv(&conn, &msg);
    if (rc == 0) {
        n_log(LOG_ERR, "FAIL(%s): n_ws_recv ACCEPTED a declared payload of %llu bytes", label, (unsigned long long)len);
        if (msg.payload)
            free_nstr(&msg.payload);
    } else {
        n_log(LOG_INFO, "PASS(%s): n_ws_recv refused a declared payload of %llu bytes", label, (unsigned long long)len);
        failed = 0;
    }

cleanup:
    netw_close(&peer);
    netw_close(&client);
    netw_close(&server);
    return failed;
}

int main(void) {
    int errors = 0;

    set_log_level(LOG_INFO);
    n_log(LOG_INFO, "n_ws_recv frame-length bound: N_WS_MAX_PAYLOAD is %zu bytes", (size_t)N_WS_MAX_PAYLOAD);

    /* the wrapping case: length + 1 for the terminator becomes 0, so the
       allocation would come back a single byte and the payload read would run
       off the end of it */
    errors += check_refused("terminator wrap", (uint64_t)SIZE_MAX - 1);
    /* the memory-exhaustion case: representable, but far past anything a real
       peer sends */
    errors += check_refused("over the cap", (uint64_t)N_WS_MAX_PAYLOAD + 1);

    if (errors > 0) {
        n_log(LOG_ERR, "ex_network_ws_limits: %d test(s) failed", errors);
        exit(1);
    }
    n_log(LOG_INFO, "ex_network_ws_limits: all checks passed");
    exit(0);
}