From: schmidt@liege.ics.uci.edu (Douglas C. Schmidt)
Subject: Problems peeking at messages using recvmsg
Newsgroups: comp.unix.solaris,comp.sys.sun.misc
Reply-To: schmidt@ics.uci.edu (Douglas C. Schmidt)
Organization: University of California at Irvine: ICS Dept.
Date: 28 Jan 93 21:43:10 GMT
Distribution: inet


Hi,

	The following program illustrates what I believe to
be a bug with Solaris 2.1.  The short client/server example below
(which runs fine with Sun OS 4.1.x) opens a file in the client and
then passes the open file descriptor to the server, which performs the
actual read.

	However, for some reason Solaris hangs if the implementation
of this functionality in the server is written as follows:

----------------------------------------
      if ((nbytes = recvmsg (n_fd, &msg, MSG_PEEK)) != -1)
	{
	  if (nbytes == sizeof a && a[0] == 0xab && a[1] == 0xcd)
	    {
	      msg.msg_accrights    = (char *) &fd;
	      msg.msg_accrightslen = sizeof fd;
	      if (recvmsg (n_fd, &msg, 0) == -1)
		{
		  perror ("recvmsg");
		  continue;
		}
	    }
	  else
	    fprintf (stderr, "say what?!\n");
	}
----------------------------------------

	Note that if I change the code to be

----------------------------------------
      if ((nbytes = recvmsg (n_fd, &msg, 0)) != -1)
	{
	  if (nbytes == sizeof a && a[0] == 0xab && a[1] == 0xcd)
	    {
	      msg.msg_accrights    = (char *) &fd;
	      msg.msg_accrightslen = sizeof fd;
	    }
	  else
	    fprintf (stderr, "say what?!\n");
	}
----------------------------------------

	Then everything works just fine with both Solaris 2.1 and Sun
OS 4.1.x.  However, the functionality is no longer the same.

	Therefore, does anyone know why Solaris would hang on the
MSG_PEEK and whether or not the code really ought to work in the first
place?!

	Thanks,

		Doug

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  fd-server.c fd-client.c
# Wrapped by schmidt@pasteur.ics.uci.edu on Thu Jan 28 13:36:26 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'fd-server.c' -a "${1}" != "-c" ; then
  echo shar: Will not clobber existing file \"'fd-server.c'\"
else
echo shar: Extracting \"'fd-server.c'\" \(2379 characters\)
sed "s/^X//" >'fd-server.c' <<'END_OF_FILE'
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/un.h>
X#include <sys/uio.h>
X#include <fcntl.h>
X#include <stdio.h>
X
X#define RENDEZVOUS "/tmp/foo"
X
X/* Server */
X
Xint
Xmain (int argc, char *argv[])
X{
X  int  s_fd;
X  int  n;
X  struct sockaddr_un uaddr;
X  char buf[BUFSIZ];
X  char *rendezvous = argc > 1 ? argv[1] : RENDEZVOUS;
X  /* Create a server */
X  unlink (rendezvous);
X
X  if ((s_fd = socket (PF_UNIX, SOCK_STREAM, 0)) == -1)
X    perror ("socket"), exit (1);
X
X  memset (&uaddr, 0, sizeof uaddr);
X  uaddr.sun_family = AF_UNIX;
X  strcpy (uaddr.sun_path, rendezvous);
X
X  if (bind (s_fd, &uaddr, sizeof uaddr) == -1)
X    perror ("bind"), exit (1);
X
X  if (listen (s_fd, 5) == -1)
X    perror ("listen"), exit (1);
X
X  /* Performs the iterative server activities */
X
X  for (;;)
X    {
X      char buf[BUFSIZ];
X      int n_fd;
X      int fd;
X      unsigned char a[2];
X      struct iovec  iov;
X      struct msghdr msg;
X      int    nbytes;
X      int    n;
X
X      /* Create a new IPC_SAP_Stream endpoint */
X      if ((n_fd = accept (s_fd, 0, 0)) == -1)
X        perror ("accept");
X
X      /* Read data from client (correctly handles incomplete reads due to flow control) */
X
X      iov.iov_base = (char *) a;
X      iov.iov_len = sizeof a;
X      msg.msg_iov = &iov;
X      msg.msg_iovlen = 1;
X      msg.msg_name = (char *) 0;
X      msg.msg_namelen = 0;
X      msg.msg_accrights	= (char *) &fd;
X      msg.msg_accrightslen = sizeof fd;
X
X      if ((nbytes = recvmsg (n_fd, &msg, MSG_PEEK)) != -1)
X	{
X	  if (nbytes == sizeof a && a[0] == 0xab && a[1] == 0xcd)
X	    {
X	      msg.msg_accrights    = (char *) &fd;
X	      msg.msg_accrightslen = sizeof fd;
X	      if (recvmsg (n_fd, &msg, 0) == -1)
X		{
X		  perror ("recvmsg");
X		  continue;
X		}
X	    }
X	  else
X	    fprintf (stderr, "say what?!\n");
X	}
X      else
X	{
X	  perror ("recvmsg PEEK failed");
X	  continue;
X	}
X
X      puts ("----------------------------------------");
X
X      while (n = read (fd, buf, sizeof buf))
X	write (1, buf, n);
X
X      puts ("----------------------------------------");
X
X      if (write (n_fd, "yow", 3) == -1)
X	perror ("write"), exit (1);
X
X      /* Close new endpoint (listening endpoint stays open) */
X      if (close (n_fd) == -1)
X        perror ("close");
X    }
X  /* NOTREACHED */
X}
END_OF_FILE
if test 2379 -ne `wc -c <'fd-server.c'`; then
    echo shar: \"'fd-server.c'\" unpacked with wrong size!
fi
# end of 'fd-server.c'
fi
if test -f 'fd-client.c' -a "${1}" != "-c" ; then
  echo shar: Will not clobber existing file \"'fd-client.c'\"
else
echo shar: Extracting \"'fd-client.c'\" \(1890 characters\)
sed "s/^X//" >'fd-client.c' <<'END_OF_FILE'
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/un.h>
X#include <sys/uio.h>
X#include <fcntl.h>
X#include <stdio.h>
X
X#define RENDEZVOUS "/tmp/foo"
X
X/* Client */
X
Xint
Xmain (int argc, char *argv[])
X{
X  char *file_name = argc > 1 ? argv[1] : "./local_data";
X  char *send_str = argc > 2 ? argv[2] : "hello world";
X  char *rendezvous = argc > 3 ? argv[3] : RENDEZVOUS;
X  int  fd;
X  int  s_fd;
X  int  n;
X  struct sockaddr_un uaddr;
X  char buf[BUFSIZ];
X  unsigned char a[2];
X  struct iovec iov;
X  struct msghdr	msg;
X
X  if ((s_fd = socket (PF_UNIX, SOCK_STREAM, 0)) == -1)
X    perror ("socket"), exit (1);
X
X  memset (&uaddr, 0, sizeof uaddr);
X  uaddr.sun_family = AF_UNIX;
X  strcpy (uaddr.sun_path, rendezvous);
X
X  if (connect (s_fd, &uaddr, sizeof uaddr.sun_family + strlen (rendezvous)) == -1)
X    perror ("connect"), exit (1);
X
X  if ((fd = open (file_name, O_RDONLY)) == -1)
X    perror ("open"), exit (1);
X
X  a[0]                   = 0xab;
X  a[1]                   = 0xcd;
X  iov.iov_base	         = (char *) a;
X  iov.iov_len		 = sizeof a;
X  msg.msg_iov		 = &iov;
X  msg.msg_iovlen	 = 1;
X  msg.msg_name		 = (char *) 0;
X  msg.msg_namelen	 = 0;
X  msg.msg_accrights	 = (char *) &fd;
X  msg.msg_accrightslen	 = sizeof fd;
X
X  if (sendmsg (s_fd, &msg, 0) == -1)
X    perror ("sendmsg"), exit (1);
X
X  if ((n = read (s_fd, buf, sizeof buf)) == -1)
X    perror ("recv"), exit (1);
X  else
X    write (1, buf, n);
X
X  /* Explicitly close the connection */
X  if (close (s_fd) == -1)
X    perror ("close"), exit (1);
X  exit (0);
X}
END_OF_FILE
if test 1890 -ne `wc -c <'fd-client.c'`; then
    echo shar: \"'fd-client.c'\" unpacked with wrong size!
fi
# end of 'fd-client.c'
fi
echo shar: End of shell archive.
exit 0
--
Douglas C. Schmidt
Department of Information and Computer Science
University of California, Irvine
Irvine, CA 92717. (714) 856-4105
Newsgroups: comp.unix.solaris,comp.sys.sun.misc