Problem w/ 4.2 sockets and OOB

litwinow at siemens.UUCP litwinow at siemens.UUCP
Tue Jul 29 08:42:00 AEST 1986


<>

We have a problem with 4.2BSD IPC using sockets in the internet
domain where both the client and server live on the same machine.
The client process sets up a signal handler which receives out of
band data sent by the server.  The client then continuously sends
500-byte blocks of data across the socket to the server.  The server
sits in an endless loop receiving data from the client.  After the
read system call has been completed, the server sends "x" number of
out of band data signals to the client.  When x is small (say 1)
everything proceeds as normal.  However, when x is large (15 in our
case), the client and server both hang.  On a VAX 11/780 running
4.2BSD and a Sun 2/50 running Sun 2.0 UNIX both processes hang.  On
the VAX, the processes terminate with a Broken Pipe.  On a Sun 3/75
running Sun UNIX 3.0 the whole machine gets hung up (whether or not
we are running suntools) and we must reboot.  A few debug statements
(and sps) show the server hangs in the select system call (presumably
waiting for data from the client) and the client hangs when trying to
write to the server.  It is important to note that this problem does
not always occur.  Seems to be some sort of a timing problem.  Has
anyone else seen this problem?  Why does it only occur when the
number of OOB signals sent is "large"?  Who breaks the communication
when the processes are hung?  Any comments, suggestions, or fixes
would be greatly appreciated.  Thanks for your help.

				Pete Litwinowicz
				princeton!siemens!litwinow

PS If you want to try this for yourself, here is a copy of the
   programs we have been using to debug this problem

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	README
#	client.c
#	server.c
# This archive created: Mon Jul 28 18:36:22 1986
export PATH; PATH=/bin:$PATH
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'

CFLAGS = -g -DDEBUG 

programs: client server
	@echo
	@echo 'programs up to date'
	@echo

server:	server.o
	cc -g -o server server.o

client: client.o
	cc -g -o client client.o


client.o:
server.o:
SHAR_EOF
fi # end of overwriting check
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
client/server routines to test hanging bug. 

% server &
% client a		- send 1 OOB for every read

 -or-

% server &
% client b		- send 15 OOBs for every read
			- this usually causes the problem
SHAR_EOF
fi # end of overwriting check
if test -f 'client.c'
then
	echo shar: will not over-write existing file "'client.c'"
else
cat << \SHAR_EOF > 'client.c'

#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>

#define FALSE 0
#define TRUE 1

int ServerFD = -1;

extern int errno;

struct _iobuf out, in;  /* buffers for the socket (one for writing and one */
                        /* for reading.                                    */

char inb[512], outb[2048];
int print,      /*  Number of times we've sent data to the server */
     rec;       /*  Number of times we've rec'd data from the server */

SIGURGhandler()
  {
  /*  Read the OOB data sent, and increment the number of times rec'd */

  char buf[5];
  rec++;
  recv(ServerFD, buf, sizeof buf, MSG_OOB);
  signal(SIGURG, SIGURGhandler);

  }


main (argc, argv)
  int argc;
  char **argv;
  {

  struct sockaddr_in sin;
  char name[50];
  int namelen = sizeof name;
  int i;
  int tries = 0;
  char sendstring[500];
  struct hostent *hp;
  int pg;

  /* Set process group ID */  
  pg = getpid();
  setpgrp(0, pg);

 
  /* get socket */
  bzero(&sin, sizeof sin);
  ServerFD = socket(AF_INET, SOCK_STREAM, 0);
  ioctl(ServerFD, SIOCSPGRP, &pg);
  
  if (ServerFD < 0)
	 exit(0);

  setsockopt(ServerFD, SOL_SOCKET, SO_USELOOPBACK, 0, 0);

  gethostname(name, namelen);
  hp = gethostbyname(name);
  if (hp == 0)
     exit(0);

  sin.sin_addr.s_addr = INADDR_ANY;
  sin.sin_family = AF_INET;
  bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
  sin.sin_port =  htons(2000);

  /* Set up SIGURG handler */
  printf("signal = %d\n", signal(SIGURG, SIGURGhandler));

  /* Connect to client */
  while (connect(ServerFD, &sin, sizeof(sin)) < 0)
      {
	 switch (errno)
	    {
	       case ECONNREFUSED: 
		     if (tries++ < 10)
			{
			   sleep(1);
			   break;
			}
	       default: 
		     return(0);
	    }
      }

  /* Set up buffers */
  in._file = ServerFD;
  out._file = ServerFD;
  in._flag=_IOREAD;
  out._flag=_IOWRT;
  setbuffer(&in, inb, 200 );
  setbuffer(&out, outb, 2048);
  
  printf("CLIENT: test print\n");

  
  if (argc<2)  
    {
    printf("This program needs an  'a' or a 'b' as its argument\n");
    exit(0);
    }
    
  /* Set up the string to send to the server */
  for (i=0;i<500;i++)
    sendstring[i]= *argv[1];
  sendstring[498]='\n';
  sendstring[499]=NULL;
  
  while (1)
    {

    print++;
    printf("rec = %d, print = %d\n", rec, print); fflush(stdout);
    printf("about to send data to server...\n"); 
    fprintf(&out,"%s",sendstring);
    fflush(&out);
    printf("sent data to server\n"); fflush(stdout);
    }
  }

      
      




SHAR_EOF
fi # end of overwriting check
if test -f 'server.c'
then
	echo shar: will not over-write existing file "'server.c'"
else
cat << \SHAR_EOF > 'server.c'

#ifndef lint
static char sccs_id[] = "%W% %H% %T% (c) Siemens RTL";
#endif

/*
  DATE CREATED: 06/03/86
*/


/* insert the appropriate includes here */
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/dir.h>
#include <sgtty.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/socket.h>

/***
***/

#define FALSE 0
#define TRUE 1


#define debug(f)    (printf f, fflush(stdout))

extern int errno;

int ClientAttachFD = -1;  /*  fd for incoming requests           */
                            /*          to connect to server.      */

int oob, r;

Send_OOB_Data(fd)
  int fd;
  {
  debug(("sending OOB %d\n", oob++));
    
  debug(("send = %d\n", send(fd, "R", 1, MSG_OOB )));

          /*  send out-of-band data.  Note that the sending of "R" is
              arbitrary... any byte of information will fit the bill.  */
  }
   





main()
  {
  int i;
  int flags;
  int fd;
  int ready;
  int fds;
  
  struct sockaddr_in sin;
  struct servent *sp;
  struct hostent *hp;
  

  bzero(&sin, sizeof sin);
  ClientAttachFD = socket(AF_INET, SOCK_STREAM, 0);
  setsockopt(ClientAttachFD, SOL_SOCKET, SO_REUSEADDR, 0, 0);
  setsockopt(ClientAttachFD, SOL_SOCKET, SO_USELOOPBACK, 0, 0);
  sin.sin_addr.s_addr = INADDR_ANY;
  sin.sin_family=AF_INET;

  sin.sin_port = htons(2000);  /* arbitrary port address.  The use
                                  of 2000 is high enough so that the
                                  bind (next statement) does not fail */

  if (bind(ClientAttachFD, &sin, sizeof sin)<0)
    {
    debug (("Bind failed\n"));
    exit (-1);
    }


  /*  Set non-blocking I/O mode for ClientAttachFD */
  flags=fcntl(ClientAttachFD,  F_GETFL, O_NDELAY);
  flags|=O_NDELAY;
  fcntl(ClientAttachFD, F_SETFL, flags);

  /* listen for clients trying to attach to the server*/
  listen(ClientAttachFD, 5);
  debug (("Listening on %d\n", ClientAttachFD));
  
    {
    struct sockaddr_in from;
    int	len;
    int flags;
   
    len= sizeof from;
    fds=1<<ClientAttachFD;
    
    while (1)
      {
      ready = select(32, &fds, 0, 0, 0);
  
      if (ready<0)
        continue;
	
      fd = accept ( ClientAttachFD, &from, &len);
      debug(("New Client Connection: %d\n", fd));
  
      /* Set non-blocking i/o mode for the socket */
      flags=fcntl(fd, F_GETFL, O_NDELAY);
      flags|=O_NDELAY;
      fcntl(fd, F_SETFL, flags);
      break;
      
      }
  

    debug (("Connection complete\n")); 
    }
 
    {
    char buf[2048];
    int n;
    register int i;
  
    
    for (;;)
      {
      while(1)
        {
	fds=1<<fd;

	debug(("Select with read mask: %x\n", fds));
        i=select (32,&fds, 0, 0, 0 );
	debug(("returned from select with read mask %x,  no fds = %d\n",
               fds, i));

	debug(("starting the read %d\n",r++));
        n = read (fd ,buf, sizeof buf);
	debug(("read %d bytes\n", n));
        if (n<0)
          exit(0);

        debug(("----------------------------------------------------\n"));
        debug(("String read:\n"));
	debug(("%s", buf)); 
        debug(("----------------------------------------------------\n"));

        /* If the first character is a 'b' send one (1) OOB message,  */
        /*  Otherwise send 15 OOB messages.                           */ 
        /*  OOB are (obviously) sent to the client that has attached  */
        /*  to the server.                                            */

        if (buf[0]!='b')  
          Send_OOB_Data(fd);
        else
          {
          for(i=0;i<15;i++)
            Send_OOB_Data(fd);
          }
        }
      }
    }
  }
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Comp.unix.wizards mailing list