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