*BSD News Article 44459


Return to BSD News archive

Xref: sserve comp.unix.bsd:16611 comp.unix.programmer:25773
Newsgroups: comp.unix.bsd,comp.unix.programmer
Path: sserve!newshost.anu.edu.au!harbinger.cc.monash.edu.au!yarrina.connect.com.au!classic.iinet.com.au!news.uoknor.edu!news.ecn.uoknor.edu!paladin.american.edu!howland.reston.ans.net!news.sprintlink.net!hookup!nstn.ns.ca!cs.dal.ca!ug!edemaine
From: edemaine@ug.cs.dal.ca (Erik Demaine)
Subject: Passing file descriptors thru rexec() socket
Message-ID: <D8xzwM.IG5@cs.dal.ca>
Sender: usenet@cs.dal.ca (USENET News)
Nntp-Posting-Host: ug.cs.dal.ca
Organization: Math, Stats & CS, Dalhousie University, Halifax, NS, Canada
X-Newsreader: TIN [version 1.2 PL2]
Date: Sun, 21 May 1995 19:09:57 GMT
Lines: 137

Hello,

I've been having some troubles passing file descriptors between a 
"parent" process and a remote "child" process.  This is not the typical 
child/parent relation;  the child was spawned using rexec().  The problem 
occurs even when the remote host is just "localhost."  I used the socket 
returned by rexec() to pass the original stdin (fd 0) to the new program.
I tried using the sendfile/recvfile (BSD 4.3 versions) from Stevens' UNIX
Network Programming book, and they didn't work -- the sendmsg (in sendfile)
gave the EINVAL (Invalid Parameter) error, probably the most non-descriptive
error message.  Note that when the processes have a parent/child relation
(spawned using execl()), these routines work great.  To further investigate,
I setup client/server programs which used datagram Berkeley sockets to pass a
file descriptor (setting msg_name and msg_namelen in the msghdr structure for
sending).  This also didn't work.

BTW, I know rexec() correctly spawned the remote child.  It prompted for 
a username/password.  As well, correct diagnostics were printed by the 
program (I read from the rexec() socket and printed any results).  I also 
tried the send_fd and recv_fd routines from Stevens' Advanced Programming in 
the UNIX Environment book.  recv_fd then gave the error "... but no file 
descriptor."

If you have any suggestions as to what my problem is, please advise.
I've enclosed the source code of my test program if you'd like to look at it.
Please respond via e-mail to edemaine@ug.cs.dal.ca.

Erik Demaine

P.S. All code was run on a SPARC 2 with SunOS 4.1.3.
-- 
Erik Demaine        || edemaine@ug.cs.dal.ca  || edemaine@fx2800.dal.ca
edemaine@cs.dal.ca  || 01ERIK@ac.dal.ca       || edemaine@is.dal.ca
URL: http://ug.cs.dal.ca:3400/~edemaine/edemaine.html
--> A glob is a round substance of thick liquid. A blob is an unformed object.

----------------------- SOURCE CODE FOLLOWS [test.c] -----------------------

#include <stdio.h>
#include <netdb.h>
#include <errno.h>

main (int argc, char *argv[])
{
   int child;
   int fd, pfd[2], nothing[2];
   char c;

   if (argc == 2)
   {
      printf ("child: Starting.\n");
      child = 1;
   } else
      child = 0;

   if (child)
   {
      fd = recv_fd (0);
      printf ("Got it: %d\n", fd);
      for (;;)
      {
         read (fd, &c, 1);
	 printf ("child: Character %c\n", c);
      }
   }
   else
   {
      int sock;
      struct servent *sp;
      char *host = "afton";
      sp = getservbyname ("exec", "tcp");
      if (sp == NULL)
         perror ("eek");
      sock = rexec (&host, sp->s_port, NULL, NULL, "/users/students/edemaine/hop/temp/test Child", 0);
      if (sock < 0)
      {
         perror ("rexec failed");
         exit (-sock);
      }
      printf ("parent: Here goes.\n");
      if (send_fd (sock, 0))
      {
         perror ("send_fd failed");
	 printf ("%d\n", errno);
	 exit (1);
      }
      printf ("parent: Enter text to write to child\n");
      while (read (sock, &c, 1) > 0)
         printf ("%c", c);
   }
}

/* UNIX Network Programming code inserted: */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>

int send_fd (int sockfd, int fd)
{
   struct iovec iov[1];
   struct msghdr msg;
   
   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;
   /* I also tried setting msg.msg_namelen to various values - no luck */
   msg.msg_accrights = (caddr_t) &fd;
   msg.msg_accrightslen = sizeof (fd);

   if (sendmsg (sockfd, &msg, 0) < 0)
      return -1;
   return 0;
}

int recv_fd (int sockfd)
{
   int fd;
   struct iovec iov[1];
   struct msghdr msg;

   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) &fd;
   msg.msg_accrightslen = sizeof (fd);

   if (recvmsg (sockfd, &msg, 0) < 0)
      return -1;
   return fd;
}

/* EOF */