0

I have several pieces of codes to establish a Unix domain socket and a service using this socket. While there are some confusing errors here leading to a failure.

the code that creats the Unix domain socket is written in c:

#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>

int main(int ac, char *av[])
{
if (ac != 4) {
    printf("Usage: %s dummy-fd sockpath binary\n", av[0]);
    exit(-1);
    }

    char *sockpn = av[2];
    char *bin = av[3];

    int srvfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (srvfd < 0) {
    perror("socket");
    exit(-1);
    }

    fcntl(srvfd, F_SETFD, FD_CLOEXEC);

    struct stat st;
    if (stat(sockpn, &st) >= 0) {
    if (!S_ISSOCK(st.st_mode)) {
        fprintf(stderr, "socket pathname %s exists and is not a socket\n",
            sockpn);
        exit(-1);
    }

    unlink(sockpn);
    }

    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    snprintf(&addr.sun_path[0], sizeof(addr.sun_path), "%s", sockpn);
    if (bind(srvfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        fprintf(stderr, "WARNING: cannot bind to socket %s (%s), exiting\n",
                sockpn, strerror(errno));
    exit(-1);
    }

    // allow anyone to connect; for access control, use directory permissions
    chmod(sockpn, 0777);

    listen(srvfd, 5);
    signal(SIGCHLD, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);

    for (;;) {
    struct sockaddr_un client_addr;
    unsigned int addrlen = sizeof(client_addr);

    int cfd = accept(srvfd, (struct sockaddr *) &client_addr, &addrlen);
    if (cfd < 0) {
        perror("accept");
        continue;
    }

    int pid = fork();
    if (pid < 0) {
        perror("fork");
        close(cfd);
        continue;
    }

    if (pid == 0) {
        // Child process
        dup2(cfd, 0);
        dup2(cfd, 1);
        close(cfd);

        execl(bin, bin, 0);
        perror("execl");
        exit(-1);
    }

    close(cfd);
    }
}

the client Python to using this sock is as follow(unixclient.py):

def call(pn, req):
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.connect(pn)
    sock.send(req)
    sock.shutdown(socket.SHUT_DOWN)
    data = ""
    while True:
        buf = sock.recv(1024)
        if not buf:
             break
        data += buf
    sock.close()
    return data

And I trigger this piece of client code in another Python code, by importing this file and call the call funciton:(Both "/jail/zoobar/echosvc" and "/jail/zoobar/echosvc/sock" will fail)

   resp = call("/jail/zoobar/echosvc", str1)

There the error occurs, showing that:

   FIle "zoobar/unixclient.py", line 8, in call
    sock.connect(pn)
   File "<string>", line 1, in connect
   error: [ERROR 2] No such file or directory

Yet I swear the directory and the socket does exist(/jail/zoobar/echosvc/sock), and the permission is correct, too(777), so I can't understand this weird error. Does anyone know about it?

I would appreciate very much for sparing time to help.

Kalzium
  • 3
  • 1
  • 5
  • I add a line `memset(&address, 0, sizeof(struct sockaddr_un));` in the first piece of code, yet the same failure. – Kalzium Feb 05 '13 at 16:42
  • `pn` is the path of domain socket, here is `"/jail/zoobar/echosvc"`, `req` is a parameter, it doesn't matter in connection. When `pn` is `"/jail/zoobar/echosvc/sock"` the same failure still occurs. – Kalzium Feb 05 '13 at 16:55
  • sorry I made a typo, the second `sock` is actually `socket`, I'll fix it immediately – Kalzium Feb 05 '13 at 16:56
  • Probably not helping you, but I have no problem running your programs on my machine. Only thing I can think of: I'm running this all under my home directory (though 777 would suggest that shouldn't matter anyway). So it doesn't look like to be the programs; more like something in the system. –  Feb 05 '13 at 17:06
  • Thank you anyway :), but I can't find other problems except the permission. – Kalzium Feb 05 '13 at 17:14

1 Answers1

1

Looks like you're trying to open the wrong filename. The code looks like:

resp = call("/jail/zoobar/echosvc", str1)

But you say "the file exists":

/jail/zoobar/echosvc/sock

Try changing your call line to:

resp = call("/jail/zoobar/echosvc/sock", str1)
John Hazen
  • 1,296
  • 1
  • 8
  • 19
  • Actually I already tried, but it doesn't work. :( Still same result. Maybe it's more like something in the system. – Kalzium Feb 05 '13 at 18:39
  • Hmm. OK. Most of the example code I've seen creates unix sockets in /tmp. Maybe there's a reason for that? Also, the "/jail/..." implies there's possibly some kind of chroot or sandboxing going on. Are you running the python script and the C program as the same user? – John Hazen Feb 05 '13 at 18:50
  • No, I don't. The C program is started by a deamon process. The python script is triggered by a .cgi file using HTTP request. They are running under different UIDs. – Kalzium Feb 05 '13 at 19:00
  • OK, so in addition to the file permissions, I believe you also need to make sure the directory is world readable (and maybe the parent directories, too). Or, figure out a spot on the filesystem where the HTTP user has access, and put the socket file there. – John Hazen Feb 05 '13 at 19:12
  • the parent directories' permissions are all 755 and the sock itself is 777, and socket file does exit within the access to HTTP user, that's...so strange... – Kalzium Feb 05 '13 at 19:18