2010-12-20 3 views
11

Я использую сокет домена UNIX для передачи дескриптора файла в другой процесс. Это отлично работает, но когда я сначала попытаюсь выяснить, может ли сокет записываться с помощью select(), вызов sendmsg() завершается с ошибкой дескриптора Bad File.Отправка дескриптора файла через сокет домена UNIX и выбор()

Функция sendmsg() отлично работает в сочетании с select(), если я не добавляю информацию о дескрипторе файла в структуру msghdr, поэтому конфликт, по-видимому, находится между select() и передачей дескрипторов файлов.

Не удалось найти информацию об этом на страницах руководства для select(), recvmsg() или любого другого. Поскольку это должно стать сервером, который передает файловые дескрипторы нескольким процессам, я все равно хотел бы использовать select().

Есть ли что-нибудь, что я могу сделать, чтобы сделать эту работу, или кто-нибудь знает об альтернативных решениях?

Платформа Ubuntu 10.4.

Это код, который инициализирует структуру:



struct cmsghdr_fd : public cmsghdr 
{ 
    int fd; 
}; 

int sendfd(int sock, int fd) 
{ 
    struct msghdr hdr; 
    struct iovec data; 
    struct cmsghdr_fd msgdata; 

    char dummy = '*'; 
    data.iov_base = &dummy; 
    data.iov_len = sizeof(dummy); 

    hdr.msg_name = NULL; 
    hdr.msg_namelen = 0; 
    hdr.msg_iov = &data; 
    hdr.msg_iovlen = 1; 
    hdr.msg_flags = 0; 

    hdr.msg_control = &msgdata; 
    hdr.msg_controllen = sizeof(msgdata); 

    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); 
    cmsg->cmsg_len = hdr.msg_controllen; 
    cmsg->cmsg_level = SOL_SOCKET; 
    cmsg->cmsg_type = SCM_RIGHTS; 

    *(int*)CMSG_DATA(cmsg) = fd; 

    int n = sendmsg(sock, &hdr, 0); 

    if(n == -1) 
    printf("sendmsg() failed: %s (socket fd = %d)\n", strerror(errno), sock); 

    return n; 
} 

Опять же, это работает, до тех пор, пока я не называю выбор() первым, чтобы проверить, готов ли для записи сокета.

+0

Можете ли вы включить свой код, который заполняет 'msghdr' и' cmsghdr'? –

+0

Я бы удостоверился, что ваш окружающий код не искажает длину msghdr (или самих данных), поскольку из очень короткого чтения обработки ядра я думаю, что это была бы вероятная проблема. – Hasturkun

+0

Я добавил код, который заполняет структур на вопрос. – svdree

ответ

10

Я пробовал код sendfd по адресу this page, который был любезно предоставлен nos, и хотя он немного отличается, он работает, даже когда я использую его в сочетании с select(). Вот как выглядит код:



    int sendfd(int sock, int fd) 
    { 
     struct msghdr hdr; 
     struct iovec data; 

     char cmsgbuf[CMSG_SPACE(sizeof(int))]; 

     char dummy = '*'; 
     data.iov_base = &dummy; 
     data.iov_len = sizeof(dummy); 

     memset(&hdr, 0, sizeof(hdr)); 
     hdr.msg_name = NULL; 
     hdr.msg_namelen = 0; 
     hdr.msg_iov = &data; 
     hdr.msg_iovlen = 1; 
     hdr.msg_flags = 0; 

     hdr.msg_control = cmsgbuf; 
     hdr.msg_controllen = CMSG_LEN(sizeof(int)); 

     struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); 
     cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 
     cmsg->cmsg_level = SOL_SOCKET; 
     cmsg->cmsg_type = SCM_RIGHTS; 

     *(int*)CMSG_DATA(cmsg) = fd; 

     int n = sendmsg(sock, &hdr, 0); 

     if(n == -1) 
     printf("sendmsg() failed: %s (socket fd = %d)\n", strerror(errno), sock); 

     return n; 
     } 

+0

Никогда не используйте 'select' больше. Я объяснил причины в своем комментарии к ОП. Используйте системный вызов 'poll' (который переносится на BSD) или' epoll'. – Omnifarious

Смежные вопросы