sendmsg () неверные аргументы (??) - PullRequest
1 голос
/ 21 февраля 2012

Сначала немного контекста: есть главная программа (веб-сервер), которая разветвляется на кучу рабочих и ждет входящих соединений. Когда он принимает один, он отправляет дескриптор сокета одному из рабочих через примитив sendmsg ().

Это код, который должен отправить дескриптор:

int send_msg (worker_t * l, struct message_t * m)
{
#ifdef __WIN32__

#else
     struct msghdr msg;                      
     struct cmsghdr * cmsg;                   
     char   anc [CMSG_SPACE (sizeof(int))]; 
     int *  fd_ptr;

     int    buf [1] = {m->msg};
     struct iovec vec;
     vec.iov_base = buf;
     vec.iov_len  = sizeof (int);

     msg.msg_iov = &vec;
     msg.msg_iovlen = 1;

     msg.msg_control = NULL;
     msg.msg_controllen = 0;

     if (m->msg == GC_SOCKET) {
          msg.msg_control = anc;
          msg.msg_controllen = sizeof anc;

          cmsg = CMSG_FIRSTHDR (&msg);
          cmsg->cmsg_level = SOL_SOCKET;
          cmsg->cmsg_type = SCM_RIGHTS;
          cmsg->cmsg_len = CMSG_LEN (sizeof (int));
          fd_ptr = (int *) CMSG_DATA (cmsg);
          *fd_ptr = m->sockfd;
          msg.msg_controllen = cmsg->cmsg_len;
     }

     msg.msg_flags = 0;

     if (sendmsg (l->channel.chan, &msg, 0) == -1) {
          i_log (1, "Unable to send message to listener.");
          return -1;
     }
     else {
          if (m->msg == GC_SOCKET && m->sockfd)
               close (m->sockfd);

          return 1;
     }
#endif
}

В приведенном выше коде l->channel.chan - это гнездо AF_UNIX, а struct message_t - это:

struct message_t {
    int msg;
    int sockfd;
};

, где msg может получить значения GC_SOCKET или GC_CLOSE. В первом случае поле sockfd содержит дескриптор переданного сокета, а во втором случае никакие вспомогательные данные не отправляются (и работник должен покончить с собой).

Теперь этот материал не работает. Вот что говорит об этом strace, когда основная программа отправляет GC_CLOSE работнику:

    ...
    [pid  6229] sendmsg(5, {msg_name(6229)={...}, msg_iov(1)=[{"\1\0\0\0", 4}],
        msg_controllen=0, msg_flags=0}, 0) = -1 EINVAL (Invalid argument)
    ...

Любая помощь очень ценится.

1 Ответ

4 голосов
/ 21 февраля 2012

Я думаю, вы не инициализируете msg.msg_name и msg.msg_namelen.Было бы безопаснее, если бы вы сделали это:

struct msghdr msg = {}

Это эквивалентно вызову memset (0) или bzero (), но более сжатым.В любом случае, прямо сейчас это выглядит так, как будто вы передаете неинициализированный кто знает что, что может легко привести к EINVAL.

Кроме того, сейчас и в будущем попробуйте запустить вашу программу под valgrind - это может помочь пойматьошибки, подобные этой.

...