Skip to content

Cant be used in Worker Threads (Error: Module did not self-register/ERR_DLOPEN_FAILED) #89

@mStirner

Description

@mStirner

I try to use raw-socket in a worker thread, which results in a ERR_DLOPEN_FAILED/Module did not self-register error.
I have a wrapper script that can be treated as cli tool or as a worker thread entry point.

When used as CLI tool, everything works like expected.
As soon as i spawn the script as a worker thread, its results in the error above.

Wrapper script:

#! /usr/bin/node

const { EOL } = require("os");
const {
    isMainThread,
    workerData,
    parentPort
} = require("worker_threads");

const WebSocket = require("ws");
const minimist = require("minimist");


const argv = minimist(process.argv, {
    boolean: ["help"],
    default: {
        upstream: "",
        socket: "tcp",
        host: "",
        port: ""
    }
});


// check arguments if used as cli client or spawend via worker thread
if ((isMainThread && (!argv.upstream || !argv.host)) || argv.help) {
    console.group("Usage of bridge.js as cli tool:", EOL);
    console.log(`bridge.js --upstream="ws://example.com" --host="127.0.0.1" --port="8080"`);
    console.log(`bridge.js --upstream="ws://open-haus.lan/api/foo/bar" --host="172.16.0.13" --socket=udp --port="53"`);
    console.log(`bridge.js --upstream="ws://127.0.0.1:8080/api/devices/663fc49985397fe02064d60d/interfaces/663fc4a06a1e907dd8e86f0e" --host="127.0.0.1" --port="8123"`);
    console.log(`bridge.js --upstream="ws://127.0.0.1:8080/api/devices/663fc4b0490a00181d03486c/interfaces/663fc4b5d6cf46265f713ba4" --host="192.168.2.1" --socket=raw`, EOL);
    console.log("--upstream\tWebSocket upstream endpoint");
    console.log("--socket\tNetwork socket type: tcp|udp|raw");
    console.log("--host\tHost to connect to");
    console.log("--port\tHost port to connect to");
    console.log("");
    process.exit(0);
}

if (!isMainThread) {
    Object.assign(argv, workerData);
}

// bridge the websocket stream to underlaying network socket
let ws = new WebSocket(argv.upstream);

ws.once("error", (err) => {

    console.error(err);
    process.exit(10);

});

ws.once("close", (code) => {
    console.log("Closed with code", code);
    process.exit();
});

ws.once("open", () => {

    let upstream = WebSocket.createWebSocketStream(ws);


    console.log("ARGV", argv);
    console.log("WorkerData", workerData)

    let socket = require(`./sockets/${argv.socket}.js`)({
        host: argv.host,
        port: argv.port
    });

    upstream.pipe(socket);
    socket.pipe(upstream);

    if (!isMainThread) {
        parentPort.on("message", (msg) => {
            if (msg === "disconnect") {

                ws.close(() => {
                    process.exit(0);
                });

            }
        });
    }

});

sockets/raw.js:

const { Duplex } = require("stream");
const raw = require("raw-socket");

// this file handles raw network sockets
// the protocol implemtnation is done on the server side
const logger = require("../system/logger.js");

module.exports = ({ host, port }, options) => {

    let socket = raw.createSocket({
        protocol: raw.Protocol.ICMP
    });

    let stream = new Duplex({
        write(chunk, encoding, cb) {

            console.log("Write to device", `raw://${host}:${port}`, chunk);

            socket.send(chunk, 0, chunk.length, host, (error, bytes) => {
                console.log("Writen to devoce")
                if (error)
                    console.log(error.toString());
            });


        },
        read(size) {
            logger.verbose(`raw://${host}:${port} Read called`, size);
        },
        end(chunk) {
            if (chunk) {
                socket.send(chunk, 0, chunk.length, host, (error, bytes) => {
                    if (error)
                        console.log(error.toString());
                });
            }
            socket.close();
        }
    });

    socket.on("error", (err) => {
        logger.error(`[error] udp://${host}:${port}`, err);
    });

    socket.on("close", () => {
        logger.debug(`[closed] udp://${host}:${port}`);
    });

    socket.on("message", (buffer, source) => {
        if (source === host) {
            console.log("received " + buffer.length + " bytes from " + source);
            stream.push(buffer);
        }
    });

    return stream;

};

Full error message:

Worker died Error: Module did not self-register: '/home/marc/projects/OpenHaus/connector/node_modules/raw-socket/build/Release/raw.node'.
    at Module._extensions..node (node:internal/modules/cjs/loader:1473:18)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at Module.require (node:internal/modules/cjs/loader:1235:19)
    at require (node:internal/modules/helpers:176:18)
    at Object.<anonymous> (/home/marc/projects/OpenHaus/connector/node_modules/raw-socket/index.js:4:11)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12) {
  code: 'ERR_DLOPEN_FAILED'
}

Debugging details:

readelf -h node_modules/raw-socket/build/Release/raw.node 
ELF-Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Klasse:                            ELF64
  Daten:                             2er-Komplement, Little-Endian
  Version:                           1 (aktuell)
  OS/ABI:                            UNIX - System V
  ABI-Version:                       0
  Typ:                               DYN (geteilte Objektadatei)
  Maschine:                          Advanced Micro Devices X86-64
  Version:                           0x1
  Einstiegspunktadresse:               0x0
  Beginn der Programm-Header:          64 (Bytes in Datei)
  Beginn der Sektions-header:          67936 (Bytes in Datei)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         11
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 30

node version: v20.11.0
npm version: v10.5.1
raw socket: v1.8.1
os: Ubuntu v23.10

An idea how to fix this?

Already tried to re-install & re-build dependencies.
But since it works as cli tool/standalone module, i think this is purposeful anyways.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions