2010-12-20 6 views
11

Estoy usando un socket de dominio UNIX para transferir un descriptor de archivo a otro proceso. Esto funciona bien, pero cuando primero intento ver si el socket es grabable usando select(), la llamada a sendmsg() falla con un error de Bad File Descriptor.Envío del descriptor de archivo sobre el socket de dominio UNIX, y seleccione()

La función sendmsg() funciona bien en combinación con select() si no agrego la información del descriptor de archivo a la estructura msghdr, por lo que el conflicto parece estar entre select() y transferir descriptores de archivo.

No he podido encontrar ninguna información sobre esto en las páginas man para select(), recvmsg(), o cualquier otro. Como esto tiene que convertirse en un servidor que distribuya descriptores de archivos a múltiples procesos, me gustaría poder usar select().

¿Hay algo que pueda hacer para que esto funcione, o alguien sabe de soluciones alternativas?

La plataforma es Ubuntu 10.4.

Este es el código que inicializa las estructuras:



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

Una vez más, esto funciona, siempre y cuando no llamo seleccionar() primero para comprobar si el zócalo esté listo para la escritura.

+0

¿Puede incluir el código que puebla 'msghdr' y' cmsghdr'? –

+0

Verificaría que el código que lo rodea no esté dañando la longitud del msghdr (o los datos en sí), ya que de una lectura muy breve del manejo del núcleo, creo que sería el problema probable – Hasturkun

+0

Agregué el código que puebla el estructuras a la pregunta. – svdree

Respuesta

10

Probé el código de envío en this page, que fue proporcionado amablemente por nos, y aunque es ligeramente diferente, funciona incluso cuando lo uso en combinación con select(). Así es como se ve el código ahora:



    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

Nunca más use 'select'. Di razones en mi comentario sobre el OP. Use la llamada al sistema 'poll' (que es portátil para BSD) o el sistema' epoll'. – Omnifarious

Cuestiones relacionadas