Passing file descriptors using recvmsg and sendmsg questions

Passing file descriptors using recvmsg and sendmsg questions

Post by Yi Qin (BCW P » Fri, 22 Nov 1991 19:30:20



Hello. I am sorry for sending this sizeable posting, but I have been crazy
after stuck with my problems for a week.

Does anyone out there have the experience of using "sendmsg" and "recvmsg"
to pass file descriptors between processes in SunOS4.1.1?

My first question is, does recvmsg block on reading the socket if the argument
data structure of msg (struct msghdr msg;) has an empty message buffer appended?

recvmsg doesn't block in my program. The relevant piece of the code is:
_____________________________
Case 1:

struct msghdr msg;
struct iovec iov[1];
int test_fd, mesg_sock;
...
mesg_sock = accept(svr_sock, (sockaddr *) 0, (int *) 0);
...
if ((test_fd = open("testfile", O_RDWR | O_CREAT)) == -1) {
    perror("open(testfile)");
    exit(1);

Quote:}

...
iov[0].iov_base         = (char *) 0;
iov[0].iov_len          = 0;
msg.msg_iov             = iov;
msg.msg_iovlen          = 1;
msg.msg_name            = (caddr_t) 0;
msg.msg_accrights       = (caddr_t) &test_fd;
msg.msg_accrightslen    = sizeof(test_fd);

if (sendmsg(mesg_sock, &msg, 0) < 0) {
    perror("sendmsg(mesg_sock)");
    exit(1);

Quote:}

...
-------------------------------------------------

But, recvmsg does block after I allocate a buffer to msg, such as
___________________________
Case 2:

char buffer[1024];

iov[0].iov_base         = (char *) buffer;
iov[0].iov_len          = sizeof(buffer);
msg.msg_iov             = iov;
msg.msg_iovlen          = 1;
msg.msg_name            = (caddr_t) 0;
msg.msg_accrights       = (caddr_t) &test_fd;
msg.msg_accrightslen    = sizeof(test_fd);
---------------------------------------------

Is this the way recvmsg works? If TRUE, the example given in Steven's
book of "Unix Network Programming" (pp308-312) wouldn't work, as it's
same as case 1, or the other way round. :-)  Otherwise, there is,
hopefully, something wrong with my code.
______________________________________________________________________
My second question, it's actually a problem, is that, when passing fd,
the sendmsg doesn't seem to like the way I give the structure msghdr
argument--invalid argument. The side effect of the sendmsg's return
with an error is that the recvmsg returns, but with nothing in msg.

Here is the complete code of the sendmsg end program. I am sorry about
the size of the code again.

Before you lose your interest to go to the code, I am saying thank you
all for your time. Please kindly reply to my email address in case there
is no popular interest in this.

Yi Qin
Dept. of Computer Science
Univ. of Manchester
Manchester m13 9PL
England


++++++++++++++++++++++++++++++

/* The server process "server.c". The server creates a file called "testfile"
 * and pass its descriptor to the client process using sendmsg (claimed to
 * be the only way in BSD).
 */

#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <errno.h>

main()
{
        struct sockaddr_in svr_name;
        struct hostent *hp;
        struct msghdr msg;
        struct iovec iov[1];
        char hostname[8];
        char buffer[1024];
        int svr_sock, mesg_sock, test_fd;
        int svr_name_len = sizeof(svr_name);

        /* The internet stream sockets are used. */
        if ((svr_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("socket(svr_sock)");
            exit(1);
        }

        /* Get the local node name--the sharing of file is local. */

        if (gethostname(hostname, 8) < 0) {
            perror("gethostname(hostname, 8)");
            exit(1);
        }

        if ((hp = gethostbyname(hostname)) == NULL) {
            perror("gethostbyname(hostname)");
            exit(1);
        }

        svr_name.sin_family      = AF_INET;
        svr_name.sin_addr.s_addr = INADDR_ANY;
        svr_name.sin_port        = 0;

        if (bind(svr_sock, (struct sockaddr *) &svr_name, svr_name_len) == -1) {
            perror("bind(svr_sock)");
            exit(1);
        }

        if (getsockname(svr_sock, (struct sockaddr *)&svr_name, &svr_name_len)
                                == -1) {
            perror("getsockname(svr_sock)");
            exit(1);
        }

        /* Announce the server port bound to svr_sock. */
        printf("server port --> #%d\n", ntohs(svr_name.sin_port));

        /* Start connection. */
        listen(svr_sock, 5);    /* Actually 1 is enough in my case. */

        mesg_sock = accept(svr_sock, (struct sockaddr *) 0, (int *) 0);

        if (mesg_sock == -1) {
            perror("accept(svr_sock)");
            exit(1);
        }

        printf("First mesg recv'd from client: %s", buffer);

        /* Ok, now let's do some real work.                          */
        /* Open a file and prepare for passing the fd to the client. */
        if ((test_fd = open("testfile", O_RDWR | O_CREAT)) == -1) {
            perror("open(test_fd)");
            exit(1);
        }

        strcpy(buffer, "anything");

        iov[0].iov_base         = (char *) buffer;
        iov[0].iov_len          = sizeof(buffer);
        msg.msg_iov             = iov;
        msg.msg_iovlen          = 1;
        msg.msg_name            = (caddr_t) 0;
        msg.msg_accrights       = (caddr_t) &test_fd;
        msg.msg_accrightslen    = sizeof(test_fd);

        /* Wait for a while to see whether the client blocks on recvmsg. */
        sleep(5);

        /* Here pass the file descriptor. */
        if (sendmsg(mesg_sock, &msg, 0) < 0) {
            perror("sendmsg(mesg_sock)");
            exit(1);
        }

        printf("server gets through sendmsg\n");

        exit(0);

Quote:}