Не удается подключить сокет домена Unix с помощью Python: нет такого файла или каталога

У меня есть несколько фрагментов кода для установки сокета домена Unix и службы, использующей этот сокет. Хотя здесь есть некоторые запутанные ошибки, ведущие к сбою.

код, который создает сокет домена Unix, написан на 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);
    }
}

клиентский Python для использования этого sock выглядит следующим образом (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

И я запускаю этот фрагмент клиентского кода в другом коде Python, импортируя этот файл и вызывая функцию call:(оба "/jail/zoobar/echosvc" и "/jail/zoobar/echosvc/sock" не будут работать)

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

Там возникает ошибка, показывающая, что:

   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

Тем не менее, я клянусь, что каталог и сокет существуют (/jail/zoobar/echosvc/sock), и разрешение тоже правильное (777), поэтому я не могу понять эту странную ошибку. Кто-нибудь знает об этом?

Я был бы очень признателен за экономию времени, чтобы помочь.


person Kalzium    schedule 05.02.2013    source источник
comment
Я добавляю строку memset(&address, 0, sizeof(struct sockaddr_un)); в первый фрагмент кода, но тот же сбой.   -  person Kalzium    schedule 05.02.2013
comment
pn это путь доменного сокета, здесь "/jail/zoobar/echosvc", req это параметр, в связке не имеет значения. Когда pn равно "/jail/zoobar/echosvc/sock", все равно происходит та же ошибка.   -  person Kalzium    schedule 05.02.2013
comment
извините, опечатка, вторая sock на самом деле socket, сейчас исправлю   -  person Kalzium    schedule 05.02.2013
comment
Возможно, вам это не поможет, но у меня нет проблем с запуском ваших программ на моей машине. Единственное, о чем я могу думать: я запускаю все это в своем домашнем каталоге (хотя 777 предполагает, что это все равно не имеет значения). Так что это не похоже на программы; больше похоже на что-то в системе.   -  person    schedule 05.02.2013
comment
В любом случае спасибо :), но я не могу найти других проблем, кроме разрешения.   -  person Kalzium    schedule 05.02.2013


Ответы (1)


Похоже, вы пытаетесь открыть файл с неправильным именем. Код выглядит так:

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

Но вы говорите, что «файл существует»:

/jail/zoobar/echosvc/sock

Попробуйте изменить линию вызова на:

resp = call("/jail/zoobar/echosvc/sock", str1)
person John Hazen    schedule 05.02.2013
comment
На самом деле я уже пытался, но это не работает. :( Все тот же результат. Может быть, это больше похоже на что-то в системе. - person Kalzium; 05.02.2013
comment
Хм. ХОРОШО. Большинство примеров кода, которые я видел, создают сокеты unix в /tmp. Может в этом есть причина? Кроме того, /jail/... подразумевает, что, возможно, происходит какой-то chroot или песочница. Вы запускаете скрипт Python и программу C от одного и того же пользователя? - person John Hazen; 05.02.2013
comment
Нет, не знаю. Программа C запускается процессом демона. Сценарий Python запускается файлом .cgi с использованием HTTP-запроса. Они работают под разными UID. - person Kalzium; 05.02.2013
comment
Итак, в дополнение к разрешениям на доступ к файлам, я считаю, что вам также необходимо убедиться, что каталог доступен для чтения всем (и, возможно, родительские каталоги тоже). Или найдите место в файловой системе, к которому у пользователя HTTP есть доступ, и поместите туда файл сокета. - person John Hazen; 05.02.2013
comment
разрешения для родительских каталогов - 755, а сам носок - 777, и файл сокета выходит из доступа к пользователю HTTP, это... так странно... - person Kalzium; 05.02.2013