Search code examples
c++node.jsbashipcunix-socket

Calling open() on a Unix domain socket failed with error "No such device or address"


I'm trying to communicate between NodeJS and C program using named pipes in linux. My server program has written in NodeJS:

'use strict';

const net = require('net');
const pipename = '/tmp/pipe1';
const fs = require('fs');

let server = net.createServer(function(socket){
        console.log('A new connection');
        socket.on('data',function(data){
                console.log(data.toString());
        });
        socket.on('end',function(){
                console.log('Closed connection');
        });
});

server.on('error',console.log);

fs.unlink(pipename,function(){
        server.listen(pipename);
})

//Test unix-socket server:
setInterval(function(){
        var stream = net.connect(pipename);
        stream.on('error',console.log);
        stream.write('hello');
        stream.end();
},2000);

However, when I want to open the pipe inside C even after the NodeJS server has already started, I get error:

const char* pipename = "/tmp/pipe1";
int hPipe = open(pipename, O_WRONLY); //Error: No such device or address

When I try to do echo 'Hello World!' > /tmp/pipe1, I get bash: /tmp/pipe1: No such device or address. But ls -l /tmp yields:

srwxr-xr-x 1 root root    0 Sep 16 03:20 pipe1

How can I solve this issue?


Solution

  • The /tmp/pipe1 is not a pipe file. It's a socket file. That's what the leading s means in srwxr-xr-x.

    And Bash's redirection like > does not support socket files. You need to use socket API to open the file.


    With strace (e.g. strace bash -c 'echo > /tmp/sockfile') we can see:

    ...
    openat(AT_FDCWD, "/tmp/sockfile", ...) = -1 ENXIO (No such device or address)
    ...
    

    So the error code is ENXIO whose corresponding error message is No such device or address. Bash is just calling standard C API (like strerror) to print the error.


    Exampe code for client side:

    int
    sock_connect(char * sockpath)
    {
        int sock_fd;
        struct sockaddr_un srv_addr = { 0 };
    
        sock_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
        if (sock_fd < 0) {
            return -1;
        }
    
        srv_addr.sun_family = AF_LOCAL;
        snprintf(srv_addr.sun_path, sizeof(srv_addr.sun_path), "%s", sockpath);
        if (connect(sock_fd, (struct sockaddr *) & srv_addr, sizeof(srv_addr)) < 0) {
            return -1;
        }
    
        return sock_fd;
    }