У меня есть фрагмент серверного кода, который отлично работает на моей машине, но не работает с 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 с тем же ядром.