Linux sendmsg возвращает EBADF с хорошим файлом - PullRequest
0 голосов
/ 29 января 2019

У меня есть фрагмент серверного кода, который отлично работает на моей машине, но не работает с EBADF на моем экземпляре Amazon EC2.Я понимаю, что образы Amazon Linux сильно изменены, но я думаю, что более вероятно, что ошибка с моей стороны.Я пытаюсь передать сокет от родительского к дочернему экземпляру, используя сокеты UNIX.

Вот код, затем я расскажу о том, что я попробовал после.Это код основного цикла сервера, чтобы прослушивать соединения, принимать их и передавать сокет другому процессу.

main.h

#define COUNT(array) sizeof array / sizeof array[0]
int id;
int server;
struct worker {
    int pid;
    int to;
};
struct worker *workers;
struct task {
    unsigned int client;
    struct sockaddr_in addr;
    socklen_t length;
};

main.c

void mainLoop() {
    INFO("Waiting for connections");
    struct task newTask;

    while(1) {
        if (++id >= NUM_WORKERS) {
            id = 0;
        }

        newTask.client = accept(server, (struct sockaddr *)&newTask.addr, &newTask.length);
        if (newTask.client < 0) {
            INFO("Accept failed with result %d and error (%d) '%s'", newTask.client, errno, strerror(errno));
            continue;
        }

        char buf[CMSG_SPACE(sizeof newTask.client)];
        struct iovec iov[] = {
            {&newTask, sizeof newTask}
        };
        struct msghdr msg = {
            NULL, 0,
            iov, COUNT(iov),
            buf, sizeof buf,
            0
        };

        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
        cmsg->cmsg_level = SOL_SOCKET;
        cmsg->cmsg_type = SCM_RIGHTS;
        cmsg->cmsg_len = CMSG_LEN(sizeof newTask.client);
        *CMSG_DATA(cmsg) = newTask.client;
        msg.msg_controllen = cmsg->cmsg_len;

        int result = sendmsg(workers[id].to, &msg, MSG_DONTWAIT);
        if (result < 0) // result = -1 on my server
            INFO("sendmsg failed with %d: (%d) '%s'", result, errno, strerror(errno));
    }
}

Работающие сокеты [id] .to были созданы с использованием socketpair, например, так:

int sockets[2];
socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets);

Мой макрос INFO - это либо fprintf для информационного журнала, либо stdout в зависимости от того, определена ли отладка, идобавляет символ новой строки в конце.

Если я удаляю секцию управляющего сообщения и устанавливаю для buf значение NULL (другими словами, не пропускаю сокет), то сообщение отправляется нормально.Кроме того, когда я вызываю fnctl с помощью F_GETFL, чтобы получить состояние всех задействованных сокетов (server, worker [id] .to и newTask.client), они все возвращают состояние 2 (O_RDWR).И опять же, он работает на моей машине, но не на сервере Amazon.

Этот код выглядит ошибочно или в Amazon есть ошибка?Что еще можно попробовать или как еще можно отладить это?

На сервере запущен CentOS 7 на экземпляре Amazon EC2.Версия ядра 4.19.Моя локальная машина - Debian Sid с тем же ядром.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...