2010-12-20 9 views
11

Używam gniazda domeny UNIX do przeniesienia deskryptora pliku do innego procesu. Działa to dobrze, ale kiedy po raz pierwszy spróbuję sprawdzić, czy gniazdo można zapisać za pomocą funkcji select(), wywołanie sendmsg() kończy się niepowodzeniem z błędem deskryptora uszkodzonego pliku.Wysyłanie deskryptora pliku przez gniazdo domeny UNIX i wybieranie()

Funkcja sendmsg() działa dobrze w połączeniu z select(), jeśli nie dodaję informacji o deskryptorze pliku do struktury msghdr, więc konflikt wydaje się być pomiędzy select() i przenoszenie deskryptorów plików.

Nie mogłem znaleźć żadnych informacji na ten temat na stronach man dla select(), recvmsg() lub innych. Ponieważ musi to stać się serwerem, który przekazuje deskryptory plików do wielu procesów, nadal chciałbym móc użyć select().

Czy jest coś, co mogę zrobić, aby to zadziałało, czy ktoś wie o alternatywnych rozwiązaniach?

Platforma to Ubuntu 10.4.

Jest to kod, który inicjuje struktur:



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; 
} 

Ponownie, to działa, jak długo nie nazywają select() najpierw sprawdzić, czy gniazdo jest gotowe do zapisu.

+0

Czy możesz dołączyć kod, który wypełnia 'msghdr' i' cmsghdr'? –

+0

Sprawdziłbym, czy twój otaczający kod nie psuje długości pliku msghdr (lub samych danych), ponieważ od bardzo krótkiego przeczytania obsługi jądra, myślę, że byłby to prawdopodobny problem. – Hasturkun

+0

Dodałem kod, który zapełnia struktury na to pytanie. – svdree

Odpowiedz

10

Próbowałem kod sendfd na this page, który został dostarczony przez nos, i chociaż jest tylko nieznacznie inny, działa nawet wtedy, gdy używam go w połączeniu z select(). Oto kod, który wygląda teraz:



    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

Nigdy nie używaj 'select' już. Podałem powody w moim komentarzu do PO. Użyj wywołania systemowego 'poll' (przenośnego dla BSD) lub systemu' epoll'. – Omnifarious

Powiązane problemy