control_ng_process() computed ng_ctx.local_ep (used only for Homer NG
message tracing, homer-enable-ng) by casting its opaque p1 argument to
socket_t* unconditionally:
.local_ep = p1 ? &(((socket_t*)p1)->local) : NULL,
p1 is not always a socket_t*: control_ng_incoming() (UDP) and
control_stream_readable() (TCP) do pass a real socket_t* there, but
both websocket transports (websocket_ng_process_generic() and
websocket_http_ng_generic() in websocket.c) pass a
struct websocket_conn* instead, since p1 is otherwise only used
opaquely, handed straight to each transport own cb() callback.
Reinterpreting a struct websocket_conn* as a socket_t* and dereferencing
->local produces a garbage-but-non-NULL pointer, which then segfaults
inside homer_send() as soon as it is actually sent to Homer -- reliably
reproducible on any NG-over-websocket connection (wss:// via
--listen-https, or plain ws://) once homer-enable-ng is also on.
Fix: add an explicit local_sock parameter to control_ng_process() (and
control_ng_process_plain(), which must keep an identical signature --
both are invoked polymorphically through the same
__typeof__(control_ng_process) cb in websocket.c) used only to build
local_ep, decoupled from p1. Both websocket call sites pass NULL, since
neither has a real listening socket_t to offer; UDP and TCP pass their
already-existing socket_t* unchanged.