3

I want to send a opened file descriptor between two different programs. So I am using ioctl with named pipes to do so. But there I am getting "Invalid argument" error for ioctl().

#include <stropts.h>
#include "accesories.c"
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>

#define MSGSIZ 63
char *fifo = "fifo";

int send_err(int fd, int errcode, const char *msg)
{
    int     n;

    if ((n = strlen(msg)) > 0)
        if (write(fd, msg, n) != n)    /* send the error message */
            return(-1);

    if (errcode >= 0)
        errcode = -1;   /* must be negative */

    if (send_fd(fd, errcode) < 0)
        return(-1);

    return(0);
}

int send_fd(int fd, int fd_to_send)
{
    char    buf[2];     /* send_fd()/recv_fd() 2-byte protocol */
    
    buf[0] = 0;         /* null byte flag to recv_fd() */
    if (fd_to_send < 0) {
        buf[1] = -fd_to_send;   /* nonzero status means error */
        if (buf[1] == 0)
            buf[1] = 1; /* -256, etc. would screw up protocol */
    } else {
        buf[1] = 0;     /* zero status means OK */
    }
    //printf("From the write %d\n",buf[0]);
    if (write(fd, buf, 2) != 2)
        return(-1);

    if (fd_to_send >= 0)
        if (ioctl(fd, I_SENDFD, fd_to_send) < 0)
        {
            printf("Eroor ::: %s\n",strerror(errno));
            return(-1);
        }
    return(0);
}




int main(int argc, char const *argv[])
{
    int fd, j, nwrite;
    char msgbuf[MSGSIZ+1];
    int fd_to_send;


    if((fd_to_send = open("vi",O_RDONLY)) < 0)
        printf("vi open failed");

    if(argc < 2)
    {
        fprintf(stderr, "Usage: sendmessage msg ... \n");
        exit(1);
    }
    /* open fifo with O_NONBLOCK set */
    if((fd = open(fifo, O_WRONLY | O_NONBLOCK)) < 0)
        printf("fifo open failed");
    
    /* send messages */
    for (j = 1; j < argc; j++)
    {
        if(strlen(argv[j]) > MSGSIZ)
        {
            fprintf(stderr, "message too long %s\n", argv[j]);
            continue;
        }
        strcpy(msgbuf, argv[j]);
        if((nwrite = write(fd, msgbuf, 6)) == -1)
            printf("message write failed");
    }

    printf("From send_fd %d \n",send_fd(fd,fd_to_send));
    
    exit(0);

}

The file accessories .h only contain some common include files nothing else. First I am sending a simple message and then calling send_fd which is first sending a 2 byte message and then have to send file descriptor using ioctl(). But it is not.

Rachid K.
  • 4,490
  • 3
  • 11
  • 30
Abhishek Gupta
  • 6,465
  • 10
  • 50
  • 82
  • 1
    How are you creating the file descriptor? I_SENDFD is a STREAMS thing and won't work with any pipe. It's also a highly obscure API. It's far (far!) more common to use the `sendmsg()` syscall to send file descriptors over Unix domain sockets instead. Is there any reason you want to use I_SENDFD? – Andy Ross Jul 06 '12 at 04:07
  • I am opening file vi to create the file descriptor. Is it is possible to send file descriptor using send message? I mean opened file descriptor not just the integer. – Abhishek Gupta Jul 06 '12 at 04:10

1 Answers1

2

It looks like linux doesn't support I_SENDFD. The comments indicate that I_SENDFD is in the documentation, but is not actually supported, and results in the error message you encountered. The wikipedia entry for STREAMS states the linux kernel does not have any support for streams. The wikipedia entry does point to a couple of third-party packages that could be used to add streams support, but LiS has not been ported to the 2.6 kernel, and OpenSS7 hasn't had any active development in 4 years.

However, linux does support something similar. This mechanism uses a special message type SCM_RIGHTS to deliver a file descriptor over a UNIX domain socket with sendmsg and obtained from recvmsg. Examples can be found with a simple web search, a complete example seems to be from the book The Linux Programming Interface, with source for sending and receiving.

jxh
  • 69,070
  • 8
  • 110
  • 193
  • I dont want to send file descriptor/socket descriptor using UNIX domain sockets. Is there any way around. – Abhishek Gupta Jul 06 '12 at 04:12
  • @knoxxs: I am sympathetic, but it is a little like saying I don't want to use eggs to make an omelet. Instead of sending it to the process, can you use `fork`/`exec` instead? – jxh Jul 06 '12 at 04:28
  • 1
    Linux supports I_SENDFD, or at least documents support for it. But it's strange and rare. Socket-based file descriptor passing is the mechanism that everyone actually uses and tests. – Andy Ross Jul 06 '12 at 04:35
  • @AndyRoss: The link I provided explained it was code that was left in that should not have been. My search for other sources support this. – jxh Jul 06 '12 at 04:50
  • Please comment on a downvote, so I know what needs to be improved, thanks! – jxh Jul 06 '12 at 04:51
  • @knoxxs: Why don't you want to use UNIX domain sockets? – jxh Jul 06 '12 at 05:08
  • I want to send fds to two different processes that doesn't have parent-child relation. Why I want anything else only to learn (more). I think there are multiple ways to do something in linux. – Abhishek Gupta Jul 06 '12 at 12:08
  • @knoxxs: That is true, but sometimes it means a lot of work. If you really want to use streams, you will have to port (and then support) one of the third-party add-ons to your linux kernel, or write your own. – jxh Jul 06 '12 at 14:37