2010-12-20 18 views
11

Sto utilizzando un socket di dominio UNIX per trasferire un descrittore di file in un altro processo. Funziona bene, ma quando provo a vedere se il socket è scrivibile usando select(), la chiamata sendmsg() fallisce con un errore Bad File Descriptor.Invio del descrittore di file tramite il socket di dominio UNIX e selezionare()

La funzione sendmsg() funziona bene in combinazione con select() se non aggiungo le informazioni del descrittore di file alla struttura msghdr, quindi il conflitto sembra essere tra select() e il trasferimento dei descrittori di file.

Non sono riuscito a trovare alcuna informazione su questo nelle pagine man di select(), recvmsg() o qualsiasi altro. Poiché questo deve diventare un server che distribuisce i descrittori di file a più processi, mi piacerebbe comunque poter usare select().

C'è qualcosa che posso fare per farlo funzionare o qualcuno sa di soluzioni alternative?

La piattaforma è Ubuntu 10.4.

Questo è il codice che inizializza le strutture:



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

Ancora una volta, questo funziona, finché io non chiamo select() prima di verificare se il socket è pronto per la scrittura.

+0

È possibile includere il codice che popola 'msghdr' e' cmsghdr'? –

+0

Verificherò che il codice circostante non sta corrompendo la lunghezza di msghdr (o i dati stessi), poiché da una lettura molto breve della gestione del kernel, penso che sarebbe il probabile problema – Hasturkun

+0

Ho aggiunto il codice che popola il codice strutture alla domanda. – svdree

risposta

10

Ho provato il codice sendfd al this page, che è stato gentilmente fornito da nos, e anche se è solo leggermente diverso, funziona anche quando lo uso in combinazione con select(). Ecco come appare il codice ora:



    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

Non usare mai 'select' più. Ho dato dei motivi nel mio commento sull'OP. Usate la chiamata di sistema 'sondaggio '(che è portatile a BSD) o il sistema' epoll'. – Omnifarious

Problemi correlati