[OpenSIPS-Devel] [OpenSIPS/opensips] 0fd7bc: janus: add WebSocket fragment reassembly (RFC 6455...

Norm Brandinger noreply at github.com
Fri Apr 17 12:38:39 UTC 2026


  Branch: refs/heads/master
  Home:   https://github.com/OpenSIPS/opensips
  Commit: 0fd7bca921c0232746d7527bda99d11e0007a779
      https://github.com/OpenSIPS/opensips/commit/0fd7bca921c0232746d7527bda99d11e0007a779
  Author: Norm Brandinger <n.brandinger at gmail.com>
  Date:   2026-04-17 (Fri, 17 Apr 2026)

  Changed paths:
    M modules/janus/janus_proc.c
    M modules/janus/ws_common.h
    M modules/janus/ws_common_defs.h

  Log Message:
  -----------
  janus: add WebSocket fragment reassembly (RFC 6455 Section 5.4) (#3840)

* janus: fix pkg memory leaks in cJSON_Print/cJSON_Parse paths

The janus module uses cJSON_InitHooks() to route all cJSON allocations
through OpenSIPS pkg_malloc. Three call sites had missing cleanup:

- janus_ipc_send_request(): cJSON_Print() result was copied to shm via
  shm_nt_str_dup() but the pkg-allocated original was never freed.
  Also added a NULL check -- under pkg exhaustion cJSON_Print returns
  NULL and the subsequent strlen(NULL) causes a crash.

- w_janus_send_request(): the cJSON tree from cJSON_Parse() was passed
  to janus_ipc_send_request() (which serializes it to shm) but
  cJSON_Delete() was never called afterward. Also added cleanup on the
  get_janus_connection_by_id() failure path.

- janus_raise_event() and handle_janus_json_request(): added NULL
  checks after cJSON_Print(). Fixed missing pkg_free(full_json) on
  the shm_strdup() failure path in handle_janus_json_request().

Together these leak ~350 bytes of pkg memory per janus_send_request()
call, leading to SIP worker pkg exhaustion and crash under sustained
load.

Fixes #3712

* janus: add WebSocket fragment reassembly (RFC 6455 Section 5.4)

The janus module WS client rejects any frame with FIN=0:
  "We do not support fragmemntation yet. Dropping..."

This breaks with Janus Gateway when using indented JSON (the default)
or when responses are large enough to exceed the transport frame size.

Add RFC 6455 compliant fragment reassembly:

- janus_ws_parse(): remove FIN=0 rejection, accept continuation frames
  (opcode 0x0), validate that control frames have FIN=1 (RFC 6455 5.5)

- janus_ws_handle_frag(): new state machine for fragment accumulation.
  TEXT/BIN+FIN=0 starts accumulation, CONT+FIN=0 appends, CONT+FIN=1
  delivers the reassembled message. Control frames pass through
  mid-fragment. Returns 0 (complete), 1 (read more), -1 (error).

- janus_ws_frag_cleanup(): cleanup helper called from all error paths,
  CLOSE handler, reconnect, and after successful delivery.

- janus_connection_read_data() and janus_connection_handler_id(): call
  janus_ws_handle_frag() before the opcode switch; reassembled messages
  use frag_buf instead of tcp.body.

- janus_reconnects(): free frag_buf on connection teardown.

Fragment state (frag_buf, frag_len, frag_size, frag_op) is per-connection
on the con_req struct. All operations run in the single-threaded JANUS
Manager reactor, so no additional locking is needed.

Design choices:
- 256KB reassembly limit (WS_MAX_FRAG_SIZE) for DoS protection
- 2x initial alloc + doubling realloc strategy (O(log n) reallocs)
- init_janus_ws_req intentionally preserves frag_* across frame resets
- Parse failure on reassembled message is terminal (no retry)

Tested with 100k fragmented messages (0 failures, flat pkg memory) and
30k concurrent messages across 8 producers, 6 connections, 4 workers.

Fixes #3712

* janus: address review feedback on fragment handling

- Remove msg_attempts reset in fragment accumulation path: conceptually
  wrong to signal "new message" when only a fragment was received, and
  the counter is not checked in the data path anyway.

- Remove {} blocks around frag_ret usage: move variable declaration to
  function scope for clarity.



To unsubscribe from these emails, change your notification settings at https://github.com/OpenSIPS/opensips/settings/notifications



More information about the Devel mailing list