OOB data not supported in unix domain

Damon Permezel damonp at daemon.UUCP
Sat Sep 15 06:57:04 AEST 1984


Index:	/sys/sys/uipc_usrreq.c 4.2BSD

Description:
	Out of band data transmissions are not supported in the UN*X
	domain, contrary to documentation.  In fact, attempted use of
	the facility will crash 4.2 as distributed.

	There were some fixes distributed to prevent the crash
	(panic mfree freeing free, if I remember correctly), in
	which case the 'not supported' error is returned for
	send oob and recieve oob.

Repeat-By:
Test programme courtesy of Ron Lunde (teklds!ronl).  I have modified it
somewhat for testing the fixes.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>

int newsock;
FILE *pout, *cout;
char oob_data[] = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234
67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234
678901234567890123456789012345678901234567890123456789";

main () /* This will demonstrate the out-of-band socket bug */
{
    static struct sockaddr sock;
    static struct sockaddr sock2;
    char * mytime();
    int s;
    int socklen;
    int amount, i;
    int rfds, nfound, xfds;
    char buffer[256];
    int size = 256;
    int pid;
    struct sigvec vec;
    extern int get_urg();
    static char msg1[] = "An apple a day will keep the PC away";
    static char msg2[] = "X";
    int res, fd, cmd, arg;
    extern int errno;

    sigsetmask(0);
    vec.sv_handler = get_urg;
    sigvec(SIGURG,&vec,0);

    if ((pid = fork()) > 0) {  /* The parent */
        pout = fopen("parentout","w");
        /* sleep long enough to let child create the socket */
        sleep(2);

        if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
            fprintf(stderr, "Parent: could not create a socket!\n");
            fflush(stderr);
            exit(1);
        }

        strcpy(sock.sa_data, "testsock");
        socklen=sizeof(sock);

        if (connect(s, &sock, socklen) < 0) {
            fprintf(stderr, "Parent: could not make a connection!\n");
            fflush(stderr);
            exit(1);
        }
        printf("Parent: Connected to the socket!\n");
        fflush(stdout);
	
        fprintf(pout,"Parent: Sending \"%s\" (normally) at %s\n",msg1,mytime());
	fflush(pout);

        amount = send (s, msg1, strlen(msg1), 0);

        printf("Going to sleep for 3 seconds...\n");
        fflush(stdout);


        sleep(3);

		for (i=1; i<512; ++i) {
	        amount = send (s, oob_data, i, MSG_OOB);
			if (amount < 0) {
				perror("send");
			}

            sleep(3);
		}

		kill(pid, 9);	/* knock off child	*/
		exit(0);
    }
    else {  /* The child */
        cout = fopen("childout","w");
        if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
            fprintf(stderr, "Child: could not create a socket!\n");
            fflush(stderr);
            exit(1);
        }
        unlink("testsock");  /* in case it's there from the last time
			        this thing was run */

        strcpy(sock.sa_data, "testsock");
        socklen=sizeof(sock);

        if (bind(s, &sock, socklen) < 0) {
            fprintf(stderr, "Child: could not bind a name to a socket!\n");
            fflush(stderr);
            exit(1);
        }

        if (listen(s,5) < 0) {
            fprintf(stderr, "Child: could not listen to a socket!\n");
            fflush(stderr);
            exit(1);
        }

        socklen = sizeof(sock2);
        if ((newsock = accept(s, &sock2, &socklen)) < 0) {
            fprintf(stderr, "Child: could not accept a connection!\n");
            fflush(stderr);
            exit(1);
        }
        printf("Child: Accepted a connection on the socket!\n");
        fflush(stdout);

        /* set the child as the receiver of SIGURG signals */
        arg = getpid();
        res = fcntl (newsock, F_SETOWN, arg);

        res = fcntl (newsock, F_GETOWN, 0);

        if (res != arg) {
            fprintf(stderr, "Child is not set to receive SIGURG\n");
		    fflush(stderr);
        }

        for (i=0;i<2;i++){
            amount = recv (newsock, buffer, size, 0);
	    if (amount < 0) {
		if (errno == EINTR) {
                    fprintf(cout, "Child: recv was interrupted\n");
	            fflush(cout);
	        }
                i--;
	    }
	    else if (amount == 0) {
                fprintf(cout, "Child: EOF on the socket\n");
	        fflush(cout);
            }
            else {
                buffer[amount] = '\0';
                fprintf(cout, "Child: Received \"%s\" at %s\n", buffer, mytime());
                fflush(cout);
            }
        }
		for (;;)
			pause();
        exit(0);
    }
}
    
get_urg() {
    char *mytime();
	char buffer[512];
	extern char *sys_errlist[];
	int amount;

    fprintf(cout,"Child: Got SIGURG signal at %s\n", mytime());
    amount = recv (newsock, buffer, 256, MSG_OOB);
	if (amount > 0) {
		buffer[amount] = '\0';
		fprintf(cout, "Child: Received \"%s\" (urg) at %s\n", buffer, mytime());
	} else {
		fprintf(cout, "get_urg: %s\n", sys_errlist[errno]);
	}
    fflush(cout);
    return;
}

char *
mytime()
{
    struct timeval t;
    struct timezone tz;
    static char hms[9];

    gettimeofday(&t, &tz);
    strncpy(hms, ctime(&(t.tv_sec))+11, 9);
    hms[8]='\0';
    return(hms);
}
Fix:
	Code has been added to uipc_usrreq.c to provide up to MLEN bytes
	of OOB data.
	Diffs follow.  The line numbers wont make too much sense.

===========/sys/sys/uipc_usrreq.c================
*** /tmp/,RCSt1020162	Fri Sep 14 13:49:37 1984
--- uipc_usrreq.c	Wed Aug 22 20:02:21 1984
***************
*** 1,5
  /*
!  * $Header: uipc_usrreq.c,v 1.2 84/03/30 19:33:53 damonp Exp $
   *
   * $Log:	uipc_usrreq.c,v $
   * Revision 1.2  84/03/30  19:33:53  damonp

--- 1,5 -----
  /*
!  * $Header: uipc_usrreq.c,v 1.3 84/08/22 20:00:09 damonp Exp $
   *
   * $Log:	uipc_usrreq.c,v $
   * Revision 1.3  84/08/22  20:00:09  damonp
***************
*** 2,7
   * $Header: uipc_usrreq.c,v 1.2 84/03/30 19:33:53 damonp Exp $
   *
   * $Log:	uipc_usrreq.c,v $
   * Revision 1.2  84/03/30  19:33:53  damonp
   * Fixed a bug that was causing the kernel to loop at network interrupt
   * level. If a unix domain socket that was listen()ing for connections was

--- 2,11 -----
   * $Header: uipc_usrreq.c,v 1.3 84/08/22 20:00:09 damonp Exp $
   *
   * $Log:	uipc_usrreq.c,v $
+  * Revision 1.3  84/08/22  20:00:09  damonp
+  * Add enhancements to allow OOB data on UNIX domain stream sockets.
+  * -dap at tek
+  * 
   * Revision 1.2  84/03/30  19:33:53  damonp
   * Fixed a bug that was causing the kernel to loop at network interrupt
   * level. If a unix domain socket that was listen()ing for connections was
***************
*** 42,48
  
  /*ARGSUSED*/
  uipc_usrreq(so, req, m, nam, rights)
! 	struct socket *so;
  	int req;
  	struct mbuf *m, *nam, *rights;
  {

--- 46,52 -----
  
  /*ARGSUSED*/
  uipc_usrreq(so, req, m, nam, rights)
! 	register struct socket *so;
  	int req;
  	struct mbuf *m, *nam, *rights;
  {
***************
*** 46,52
  	int req;
  	struct mbuf *m, *nam, *rights;
  {
! 	struct unpcb *unp = sotounpcb(so);
  	register struct socket *so2;
  	int error = 0;
  

--- 50,56 -----
  	int req;
  	struct mbuf *m, *nam, *rights;
  {
! 	struct unpcb *unp = sotounpcb(so), *unp2;
  	register struct socket *so2;
  	int error = 0;
  
***************
*** 221,227
  /* END UNIMPLEMENTED HOOKS */
  
  	case PRU_RCVOOB:
! 		break;
  
  	case PRU_SENDOOB:
  		break;

--- 225,251 -----
  /* END UNIMPLEMENTED HOOKS */
  
  	case PRU_RCVOOB:
! 		/*
! 		 * recieve out of band data. -dap at tek
! 		 */
! 		switch (so->so_type) {
! 		case SOCK_STREAM:
! 			if (so->so_oobmark == 0
! 			&&  (so->so_state & SS_RCVATMARK) == 0) {
! 				error = EINVAL;	/* no OOB data to recv	*/
! 				break;
! 			}
! 			if (unp->unp_oob == 0) {
! 				/*
! 				 * no data to recv. must have just
! 				 * recv''d it. Personally, I think both
! 				 * this error and the above should be the
! 				 * same, but I am being compatable with
! 				 * the TCP stuff. -dap at tek
! 				 */
! 				error = EWOULDBLOCK;
! 				break;
! 			}
  
  			/*
  			 * link the OOB data mbuf to the mbuf we were
***************
*** 223,228
  	case PRU_RCVOOB:
  		break;
  
  	case PRU_SENDOOB:
  		break;
  

--- 247,268 -----
  				break;
  			}
  
+ 			/*
+ 			 * link the OOB data mbuf to the mbuf we were
+ 			 * passed. the caller will free both these mbufs.
+ 			 * -dap at tek
+ 			 */
+ 			m->m_len = 0;
+ 			m->m_next = unp->unp_oob;
+ 			unp->unp_oob = 0;
+ 			break;
+ 
+ 		default:
+ 			error = EOPNOTSUPP;
+ 			break;
+ 		}
+ 		return (error);
+ 
  	case PRU_SENDOOB:
  		/*
  		 * send OOB data. At most MLEN bytes will be sent.
***************
*** 224,229
  		break;
  
  	case PRU_SENDOOB:
  		break;
  
  	case PRU_SOCKADDR:

--- 264,323 -----
  		return (error);
  
  	case PRU_SENDOOB:
+ 		/*
+ 		 * send OOB data. At most MLEN bytes will be sent.
+ 		 * At most one outstanding request will be allowed.
+ 		 * -dap at tek
+ 		 */
+ 		switch (so->so_type) {
+ 		case SOCK_STREAM:
+ 			if (unp->unp_conn == 0)
+ 				panic("uipc 5");
+ 
+ 			so2  = unp->unp_conn->unp_socket;
+ 			unp2 = sotounpcb(so2);
+ 
+ 			if (unp2->unp_oob) {
+ 				/*
+ 				 * must wait for the preceeding OOB data
+ 				 * to be handled. -dap at tek
+ 				 */
+ 				error = EWOULDBLOCK;
+ 				break;
+ 			}
+ 
+ 			/*
+ 			 * make sure there is at most MLEN bytes of data.
+ 			 * (this is to place a bound on the amt of mbufs that
+ 			 *  may be wasted if the recv()er never asks for
+ 			 *  OOB data) -dap at tek
+ 			 */
+ 			{
+ 				register int size = 0;
+ 				register struct mbuf *n;
+ 
+ 				for (n = m; n; n = n->m_next) {
+ 					size += n->m_len;
+ 					if (size > MLEN) {
+ 						error = EMSGSIZE;
+ 						break;
+ 					}
+ 				}
+ 			}
+ 			if (error)
+ 				break;
+ 
+ 			unp2->unp_oob = m;
+ 
+ 			if ((so2->so_oobmark = so2->so_rcv.sb_cc) == 0)
+ 				so2->so_state |= SS_RCVATMARK;
+ 
+ 			sohasoutofband(so2);
+ 			return (0);		/* don't release mbuf chain */
+ 
+ 		default:
+ 			error = EOPNOTSUPP;
+ 		}
  		break;
  
  	case PRU_SOCKADDR:
***************
*** 282,287
  	soisdisconnected(unp->unp_socket);
  	unp->unp_socket->so_pcb = 0;
  	m_freem(unp->unp_remaddr);
  	(void) m_free(dtom(unp));
  }
  

--- 376,386 -----
  	soisdisconnected(unp->unp_socket);
  	unp->unp_socket->so_pcb = 0;
  	m_freem(unp->unp_remaddr);
+ 	/*
+ 	 * free any unrecv''d OOB data mbufs. -dap at tek
+ 	 */
+ 	if (unp->unp_oob)
+ 		m_freem(unp->unp_oob);
  	(void) m_free(dtom(unp));
  }
  
===========/sys/h/unpcb.h================
*** /tmp/,RCSt1020230	Fri Sep 14 13:50:51 1984
--- unpcb.h	Wed Aug 22 22:41:35 1984
***************
*** 1,5
  /*
!  * $Header: unpcb.h,v 1.1 83/12/09 13:00:03 avatar Exp $
   *
   * $Log:	unpcb.h,v $
   * Revision 1.1  83/12/09  13:00:03  avatar

--- 1,5 -----
  /*
!  * $Header: unpcb.h,v 1.2 84/08/22 20:03:16 damonp Exp $
   *
   * $Log:	unpcb.h,v $
   * Revision 1.2  84/08/22  20:03:16  damonp
***************
*** 2,7
   * $Header: unpcb.h,v 1.1 83/12/09 13:00:03 avatar Exp $
   *
   * $Log:	unpcb.h,v $
   * Revision 1.1  83/12/09  13:00:03  avatar
   * Initial revision
   * 

--- 2,11 -----
   * $Header: unpcb.h,v 1.2 84/08/22 20:03:16 damonp Exp $
   *
   * $Log:	unpcb.h,v $
+  * Revision 1.2  84/08/22  20:03:16  damonp
+  * Add field so that protocol can keep track of OOB data.
+  * -dap at tek
+  * 
   * Revision 1.1  83/12/09  13:00:03  avatar
   * Initial revision
   * 
***************
*** 28,33
   * by a number of other sockets and may also reference a socket (not
   * necessarily one which is referencing it).  This generates
   * the need for unp_refs and unp_nextref to be separate fields.
   */
  struct	unpcb {
  	struct	socket *unp_socket;	/* pointer back to socket */

--- 32,39 -----
   * by a number of other sockets and may also reference a socket (not
   * necessarily one which is referencing it).  This generates
   * the need for unp_refs and unp_nextref to be separate fields.
+  *
+  * An mbuf ^ has been added to allow OOB data. -dap at tek
   */
  struct	unpcb {
  	struct	socket *unp_socket;	/* pointer back to socket */
***************
*** 36,41
  	struct	unpcb *unp_refs;	/* referencing socket linked list */
  	struct 	unpcb *unp_nextref;	/* link in unp_refs list */
  	struct	mbuf *unp_remaddr;	/* address of connected socket */
  };
  
  #define	sotounpcb(so)	((struct unpcb *)((so)->so_pcb))

--- 42,48 -----
  	struct	unpcb *unp_refs;	/* referencing socket linked list */
  	struct 	unpcb *unp_nextref;	/* link in unp_refs list */
  	struct	mbuf *unp_remaddr;	/* address of connected socket */
+ 	struct	mbuf *unp_oob;		/* out of band data	*/
  };
  
  #define	sotounpcb(so)	((struct unpcb *)((so)->so_pcb))



More information about the Comp.bugs.4bsd.ucb-fixes mailing list