brad@bradley.bradley.edu (Bradley E. Smith) (02/20/91)
Submitted-by: brad@bradley.bradley.edu (Bradley E. Smith) Posting-number: Volume 1, Issue 10 Archive-name: uipc/part03 # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by bradley!brad on Fri Feb 15 22:36:29 CST 1991 # Contents: uipc/src/Makefile uipc/src/s.c uipc/src/select.c uipc/src/select.h # uipc/src/slave.side uipc/src/socket1.c uipc/src/socket2.c # uipc/src/syscalls.c uipc/src/sysent.m4 uipc/src/usrreq.c echo x - uipc/src/Makefile sed 's/^@//' > "uipc/src/Makefile" <<'@//E*O*F uipc/src/Makefile//' # Merged Makefile from pty drive below # # Eric H. Herrin II # University of Kentucky Mathematical Sciences Laboratories # 915 Patterson Office Tower # University of Kentucky # Lexington, KY 40506 # eric@ms.uky.edu, ..!cbosgd!ukma!eric # # # and Makefile from socket stuff # # @(#)Makefile 1.1 (Alex Crain) 6/20/89 # # Makefile for UnixPc uipc driver. # Written By Alex Crain # # Added select & pty code # SHELL=/bin/sh MV=/bin/mv RM=/bin/rm # on my gcc I need to add -v flag to CFLAGS or else # gcc will die on me periodically - bes # # CC=gcc # CC=cc IFLAGS=-I../ OFLAG=-O # define DEBUG for debuggin messages DEFS= -UDEBUG -DSYSV -DUNIXPC -DSELECT CFLAGS=$(OFLAG) $(IFLAGS) -DKERNEL=1 $(DEFS) $(VFLAG) LD=/bin/ld #LIBS=-lgcc # see ../Makefile #LIBS=/usr/local/lib/gcc-gnulib LINT=lint SOURCES=mbuf.c domain.c socket1.c socket2.c syscalls.c proto.c usrreq.c \ interface.c debug.c sysent.m4 pty.c linesw.c select.c OBJS=mbuf.o domain.o socket1.o socket2.o syscalls.o proto.o usrreq.o \ interface.o debug.o pty.o linesw.o select.o all: ../pty.o remove: (cd ..;${SHELL} Remove) @.c.o: $(CC) $(CFLAGS) -c $*.c sysent.h: ../sysconfig.m4 sysent.m4 m4 sysent.m4 > sysent.h @../pty.o: $(OBJS) ld -r -n -o ../pty.o $(OBJS) $(LIB) depend: sysent.h cat Makefile | sed -e "/^### DEPEND LINE/q" > Make.tmp $(CC) $(IFLAGS) -M $(SOURCES) >> Make.tmp $(MV) Make.tmp Makefile clean: $(RM) -f *.o ../uipc.o core sysent.h lint: $(LINT) $(IFLAGS) $(SOURCES) > lint.out ### DEPEND LINE --- do not delete! mbuf.o : mbuf.c /usr/include/sys/types.h /usr/include/sys/param.h \ /usr/include/sys/types.h /usr/include/sys/sysmacros.h \ /usr/include/sys/systm.h /usr/include/sys/param.h /usr/include/sys/inode.h \ /usr/include/sys/proc.h /usr/include/sys/types.h /usr/include/sys/text.h \ /usr/include/sys/types.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/param.h /usr/include/sys/shm.h /usr/include/sys/ipc.h \ /usr/include/sys/types.h /usr/include/sys/pte.h /usr/include/sys/param.h \ /usr/include/sys/pte.h /usr/include/sys/buf.h /usr/include/sys/param.h \ /usr/include/sys/inode.h /usr/include/sys/proc.h /usr/include/sys/filsys.h \ /usr/include/sys/param.h /usr/include/sys/ino.h /usr/include/sys/file.h \ /usr/include/sys/types.h /usr/include/sys/inode.h /usr/include/sys/filsys.h \ /usr/include/sys/cmap.h ..//uipc/socketvar.h ..//uipc/conf.h \ ..//uipc/protosw.h ..//uipc/conf.h ..//uipc/domain.h \ ..//uipc/conf.h ..//uipc/mbuf.h ..//uipc/conf.h ..//uipc/fproto.h domain.o : domain.c /usr/include/sys/types.h /usr/include/sys/param.h \ /usr/include/sys/types.h /usr/include/sys/sysmacros.h \ /usr/include/sys/systm.h /usr/include/sys/param.h /usr/include/sys/inode.h \ /usr/include/sys/proc.h /usr/include/sys/types.h /usr/include/sys/text.h \ /usr/include/sys/types.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/param.h /usr/include/sys/shm.h /usr/include/sys/ipc.h \ /usr/include/sys/types.h /usr/include/sys/pte.h /usr/include/sys/param.h \ /usr/include/sys/pte.h /usr/include/sys/buf.h /usr/include/sys/param.h \ /usr/include/sys/inode.h /usr/include/sys/proc.h /usr/include/sys/filsys.h \ /usr/include/sys/param.h /usr/include/sys/ino.h /usr/include/sys/file.h \ /usr/include/sys/types.h /usr/include/sys/inode.h /usr/include/sys/filsys.h \ /usr/include/sys/cmap.h ..//uipc/socketvar.h ..//uipc/conf.h \ ..//uipc/socket.h ..//uipc/conf.h ..//uipc/protosw.h \ ..//uipc/conf.h ..//uipc/domain.h ..//uipc/conf.h ..//uipc/mbuf.h \ ..//uipc/conf.h ..//uipc/fproto.h socket1.o : socket1.c /usr/include/sys/types.h /usr/include/sys/param.h \ /usr/include/sys/types.h /usr/include/sys/sysmacros.h \ /usr/include/sys/systm.h /usr/include/sys/param.h /usr/include/sys/inode.h \ /usr/include/sys/proc.h /usr/include/sys/types.h /usr/include/sys/text.h \ /usr/include/sys/types.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/param.h /usr/include/sys/shm.h /usr/include/sys/ipc.h \ /usr/include/sys/types.h /usr/include/sys/pte.h /usr/include/sys/param.h \ /usr/include/sys/pte.h /usr/include/sys/buf.h /usr/include/sys/param.h \ /usr/include/sys/inode.h /usr/include/sys/proc.h /usr/include/sys/filsys.h \ /usr/include/sys/param.h /usr/include/sys/ino.h /usr/include/sys/file.h \ /usr/include/sys/types.h /usr/include/sys/inode.h /usr/include/sys/filsys.h \ /usr/include/sys/cmap.h /usr/include/sys/user.h /usr/include/sys/types.h \ /usr/include/sys/param.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/file.h /usr/include/sys/dmap.h /usr/include/sys/types.h \ /usr/include/sys/signal.h /usr/include/sys/vlimit.h \ /usr/include/sys/dir.h /usr/include/sys/types.h /usr/include/sys/proc.h \ /usr/include/sys/file.h /usr/include/sys/var.h /usr/include/sys/errno.h \ ..//uipc/mbuf.h ..//uipc/conf.h ..//uipc/socket.h ..//uipc/conf.h \ ..//uipc/socketvar.h ..//uipc/conf.h ..//uipc/domain.h \ ..//uipc/conf.h ..//uipc/protosw.h ..//uipc/conf.h \ ..//uipc/fproto.h socket2.o : socket2.c /usr/include/sys/types.h /usr/include/sys/param.h \ /usr/include/sys/types.h /usr/include/sys/sysmacros.h \ /usr/include/sys/systm.h /usr/include/sys/param.h /usr/include/sys/inode.h \ /usr/include/sys/proc.h /usr/include/sys/types.h /usr/include/sys/text.h \ /usr/include/sys/types.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/param.h /usr/include/sys/shm.h /usr/include/sys/ipc.h \ /usr/include/sys/types.h /usr/include/sys/pte.h /usr/include/sys/param.h \ /usr/include/sys/pte.h /usr/include/sys/buf.h /usr/include/sys/param.h \ /usr/include/sys/inode.h /usr/include/sys/proc.h /usr/include/sys/filsys.h \ /usr/include/sys/param.h /usr/include/sys/ino.h /usr/include/sys/file.h \ /usr/include/sys/types.h /usr/include/sys/inode.h /usr/include/sys/filsys.h \ /usr/include/sys/cmap.h /usr/include/sys/errno.h /usr/include/sys/proc.h \ /usr/include/sys/var.h ..//uipc/mbuf.h ..//uipc/conf.h \ ..//uipc/socket.h ..//uipc/conf.h ..//uipc/socketvar.h \ ..//uipc/conf.h ..//uipc/protosw.h ..//uipc/conf.h \ ..//uipc/domain.h ..//uipc/conf.h ..//uipc/fproto.h syscalls.o : syscalls.c /usr/include/sys/types.h /usr/include/sys/param.h \ /usr/include/sys/types.h /usr/include/sys/sysmacros.h \ /usr/include/sys/systm.h /usr/include/sys/param.h /usr/include/sys/inode.h \ /usr/include/sys/proc.h /usr/include/sys/types.h /usr/include/sys/text.h \ /usr/include/sys/types.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/param.h /usr/include/sys/shm.h /usr/include/sys/ipc.h \ /usr/include/sys/types.h /usr/include/sys/pte.h /usr/include/sys/param.h \ /usr/include/sys/pte.h /usr/include/sys/buf.h /usr/include/sys/param.h \ /usr/include/sys/inode.h /usr/include/sys/proc.h /usr/include/sys/filsys.h \ /usr/include/sys/param.h /usr/include/sys/ino.h /usr/include/sys/file.h \ /usr/include/sys/types.h /usr/include/sys/inode.h /usr/include/sys/filsys.h \ /usr/include/sys/cmap.h /usr/include/sys/user.h /usr/include/sys/types.h \ /usr/include/sys/param.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/file.h /usr/include/sys/dmap.h /usr/include/sys/types.h \ /usr/include/sys/signal.h /usr/include/sys/vlimit.h \ /usr/include/sys/dir.h /usr/include/sys/types.h /usr/include/sys/file.h \ /usr/include/sys/buf.h /usr/include/sys/errno.h /usr/include/sys/systm.h \ ..//uipc/mbuf.h ..//uipc/conf.h ..//uipc/socket.h ..//uipc/conf.h \ ..//uipc/socketvar.h ..//uipc/conf.h ..//uipc/domain.h \ ..//uipc/conf.h ..//uipc/protosw.h ..//uipc/conf.h \ ..//uipc/un.h ..//uipc/conf.h ..//uipc/fproto.h proto.o : proto.c /usr/include/sys/types.h /usr/include/sys/param.h \ /usr/include/sys/types.h /usr/include/sys/sysmacros.h \ /usr/include/sys/systm.h /usr/include/sys/param.h /usr/include/sys/inode.h \ /usr/include/sys/proc.h /usr/include/sys/types.h /usr/include/sys/text.h \ /usr/include/sys/types.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/param.h /usr/include/sys/shm.h /usr/include/sys/ipc.h \ /usr/include/sys/types.h /usr/include/sys/pte.h /usr/include/sys/param.h \ /usr/include/sys/pte.h /usr/include/sys/buf.h /usr/include/sys/param.h \ /usr/include/sys/inode.h /usr/include/sys/proc.h /usr/include/sys/filsys.h \ /usr/include/sys/param.h /usr/include/sys/ino.h /usr/include/sys/file.h \ /usr/include/sys/types.h /usr/include/sys/inode.h /usr/include/sys/filsys.h \ /usr/include/sys/cmap.h ..//uipc/mbuf.h ..//uipc/conf.h \ ..//uipc/socket.h ..//uipc/conf.h ..//uipc/socketvar.h \ ..//uipc/conf.h ..//uipc/protosw.h ..//uipc/conf.h \ ..//uipc/domain.h ..//uipc/conf.h ..//uipc/fproto.h usrreq.o : usrreq.c /usr/include/sys/types.h ..//uipc/conf.h \ /usr/include/sys/param.h /usr/include/sys/types.h /usr/include/sys/sysmacros.h \ /usr/include/sys/systm.h /usr/include/sys/param.h /usr/include/sys/inode.h \ /usr/include/sys/proc.h /usr/include/sys/types.h /usr/include/sys/text.h \ /usr/include/sys/types.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/param.h /usr/include/sys/shm.h /usr/include/sys/ipc.h \ /usr/include/sys/types.h /usr/include/sys/pte.h /usr/include/sys/param.h \ /usr/include/sys/pte.h /usr/include/sys/buf.h /usr/include/sys/param.h \ /usr/include/sys/inode.h /usr/include/sys/proc.h /usr/include/sys/filsys.h \ /usr/include/sys/param.h /usr/include/sys/ino.h /usr/include/sys/file.h \ /usr/include/sys/types.h /usr/include/sys/inode.h /usr/include/sys/filsys.h \ /usr/include/sys/cmap.h /usr/include/sys/user.h /usr/include/sys/types.h \ /usr/include/sys/param.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/file.h /usr/include/sys/dmap.h /usr/include/sys/types.h \ /usr/include/sys/signal.h /usr/include/sys/vlimit.h \ /usr/include/sys/dir.h /usr/include/sys/types.h /usr/include/sys/inode.h \ /usr/include/sys/proc.h /usr/include/sys/stat.h /usr/include/sys/types.h \ /usr/include/sys/var.h /usr/include/sys/tune.h /usr/include/sys/types.h \ /usr/include/sys/errno.h ..//uipc/mbuf.h ..//uipc/conf.h \ ..//uipc/socket.h ..//uipc/conf.h ..//uipc/socketvar.h \ ..//uipc/conf.h ..//uipc/protosw.h ..//uipc/conf.h \ ..//uipc/domain.h ..//uipc/conf.h ..//uipc/unpcb.h \ ..//uipc/conf.h ..//uipc/un.h ..//uipc/conf.h ..//uipc/fproto.h interface.o : interface.c /usr/include/sys/types.h \ /usr/include/sys/systm.h /usr/include/sys/param.h /usr/include/sys/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/inode.h \ /usr/include/sys/proc.h /usr/include/sys/types.h /usr/include/sys/text.h \ /usr/include/sys/types.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/param.h /usr/include/sys/shm.h /usr/include/sys/ipc.h \ /usr/include/sys/types.h /usr/include/sys/pte.h /usr/include/sys/param.h \ /usr/include/sys/pte.h /usr/include/sys/buf.h /usr/include/sys/param.h \ /usr/include/sys/inode.h /usr/include/sys/proc.h /usr/include/sys/filsys.h \ /usr/include/sys/param.h /usr/include/sys/ino.h /usr/include/sys/file.h \ /usr/include/sys/types.h /usr/include/sys/inode.h /usr/include/sys/filsys.h \ /usr/include/sys/cmap.h /usr/include/sys/errno.h /usr/include/sys/user.h \ /usr/include/sys/types.h /usr/include/sys/param.h /usr/include/sys/proc.h \ /usr/include/sys/inode.h /usr/include/sys/file.h /usr/include/sys/dmap.h \ /usr/include/sys/types.h /usr/include/sys/signal.h \ /usr/include/sys/vlimit.h /usr/include/sys/dir.h /usr/include/sys/types.h \ ..//uipc/socketvar.h ..//uipc/conf.h ..//uipc/mbuf.h \ ..//uipc/conf.h ..//uipc/protosw.h ..//uipc/conf.h \ ..//uipc/domain.h ..//uipc/conf.h ..//uipc/fproto.h \ sysent.h debug.o : debug.c /usr/include/sys/types.h /usr/include/sys/param.h \ /usr/include/sys/types.h /usr/include/sys/sysmacros.h \ /usr/include/sys/systm.h /usr/include/sys/param.h /usr/include/sys/inode.h \ /usr/include/sys/proc.h /usr/include/sys/types.h /usr/include/sys/text.h \ /usr/include/sys/types.h /usr/include/sys/proc.h /usr/include/sys/inode.h \ /usr/include/sys/param.h /usr/include/sys/shm.h /usr/include/sys/ipc.h \ /usr/include/sys/types.h /usr/include/sys/pte.h /usr/include/sys/param.h \ /usr/include/sys/pte.h /usr/include/sys/buf.h /usr/include/sys/param.h \ /usr/include/sys/inode.h /usr/include/sys/proc.h /usr/include/sys/filsys.h \ /usr/include/sys/param.h /usr/include/sys/ino.h /usr/include/sys/file.h \ /usr/include/sys/types.h /usr/include/sys/inode.h /usr/include/sys/filsys.h \ /usr/include/sys/cmap.h /usr/include/sys/errno.h /usr/include/sys/proc.h \ ..//uipc/mbuf.h ..//uipc/conf.h ..//uipc/socket.h ..//uipc/conf.h \ ..//uipc/socketvar.h ..//uipc/conf.h ..//uipc/protosw.h \ ..//uipc/conf.h ..//uipc/domain.h ..//uipc/conf.h @//E*O*F uipc/src/Makefile// chmod u=rw,g=r,o=r uipc/src/Makefile echo x - uipc/src/s.c sed 's/^@//' > "uipc/src/s.c" <<'@//E*O*F uipc/src/s.c//' /* * syscalls.c - system call kernal interface routines. * * Written by Alex Crain. * Extensivly hacked by Brad Bosch. * * I don't think there is anything left here to which this applies, but... * * This file is based in the Berkeley file uipc_syscalls.c, * but is *not* guarenteed to be in any way compatable. It is * close enough to the Berkeley code that the following applies... * * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided "as is" without express or implied warranty. * */ #include "pty.h" #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/user.h> #include <sys/file.h> #include <sys/buf.h> #include <sys/errno.h> #include <sys/systm.h> #include <sys/tty.h> #include <sys/conf.h> #include <sys/var.h> #include <uipc/mbuf.h> #include <uipc/socket.h> #include <uipc/socketvar.h> #include <uipc/domain.h> #include <uipc/protosw.h> #include <uipc/un.h> #include <uipc/fproto.h> #include <uipc/unpcb.h> #include "select.h" void unselect(); extern int pty_major; /* we will need this in the select loop */ extern struct proc *pty_proc[]; /* selecting process for each master */ /* This returns a pointer to the tty structure for a device number. * Returns NULL if unknown or error. This works for tty*, console, and ttyp*. * extern struct tty * gettty(); * The above didn't work for ph*. Have to write our own. See below. */ /* we now sleep on ldmisc[SEL_REGISTER] since this is known to other drivers*/ /* Table of driver's select poll entry points indexed by major number */ static int (*poll_table[NUM_SEL_DRIVERS])(); extern struct tty *pser_tty[]; /* replacement gettty for broken one in kernel */ struct tty * gettty(dev) dev_t dev; { register int maj, min; maj = major(dev); if (maj >= cdevcnt) return(NULL); min = minor(dev); switch (maj) { case 0: /* tty000 */ /* these are hardcoded in kernel too! */ return (pser_tty[min]); case 8: /* ph* */ return (pser_tty[1]); case 7: /* win* */ if (min < 12) return (&(cdevsw[maj].d_ttys)[min-1]); else return (NULL); default: /* other normal cases */ return (&(cdevsw[maj].d_ttys)[min]); } } void selwakeup(); /* forward reference comming */ /* * This is called by other drivers to register their select routine with us. * We return the address of the routine which the driver should call when i/o * may be possible on a device which is under selection. The driver should * save this address for later use. The address of se_register is stored in * ldmisc[SEL_REGISTER] for reference by other drivers. */ void (*se_register (poll_routine, maj_dev))() int (*poll_routine)(); int maj_dev; { # ifdef DEBUG eprintf("se_register: maj_dev=%d, poll_routine=%x\n", maj_dev, poll_routine); # endif if (maj_dev < NUM_SEL_DRIVERS) poll_table[maj_dev] = poll_routine; return(selwakeup); } /* seselect () /* */ select () /* */ { register struct a { int nfds; int *readfds; int *writefds; int *execptfds; struct timeval *timeout; } * uap = (struct a *) u.u_ap; int mask, cnt, tim, timout, rds; int i, j, k, l, s; dev_t rdev; struct timeval utimeout; struct file *fp; struct inode *ip; struct tty *tp; struct socket *so; /* * If timeout specified, convert time to hz and set timer. */ /* select_timed_out = 0; */ u.u_procp->p_flag &= ~STIMO; tim = -1; if ( uap->timeout ) { if (copyin(uap->timeout, &utimeout, sizeof(utimeout))) { u.u_error = EINVAL; return; } tim = utimeout.tv_sec * HZ + utimeout.tv_usec * 6/100000; # ifdef DEBUG eprintf("select: timeout set to %d\n", tim); # endif if (tim) timout = timeout(unselect, u.u_procp, tim); } if (uap->nfds > 32) uap->nfds = 32; # ifdef DEBUG eprintf("select: rds=%x nfds=%d\n", *uap->readfds, uap->nfds); # endif poll: u.u_procp->p_flag |= SSEL; cnt = 0; if(uap->readfds) { /* have readbitmask */ rds = fuword(uap->readfds); for(i=0;i < uap->nfds; i++) { u.u_error = 0; /* reset it */ mask = 1 << i; if(rds & mask) { /* is this one? */ # ifdef DEBUGA eprintf("select: mask=%d getf=%d ofile=%d, i=%d\n", mask, getf(i), u.u_ofile[i], i); # endif /* here is some code for sockets */ fp = getsock(i); if(fp != 0) { /* valid socket */ so = filesock(fp); j = (SS_CANTRCVMORE | SS_CANTSENDMORE); k = SS_ISCONNECTED; /* first check for closed sockets * closed sockets appear only to have j set */ if((so->so_state & j) == j) { /* socket is close. mark as having * data on it, so a read will fail */ cnt++; } /* next we check for a state of incomming ie * accept needs to be called */ else if ( so->so_qlen ) { cnt++; } /* and this is for regular sockets already * connected */ else if( (so->so_rcv.sb_mb != 0) && (so->so_rcv.sb_cc != 0)) { /* has buffer & has chars */ cnt++; } else { rds &= ~mask; } } else if((fp = getf(i)) != 0) { /* valid open file */ ip = fp->f_inode; rdev = (dev_t) ip->i_rdev; # ifdef DEBUG eprintf("select: fd=%d dev id=%x tp=%x\n", i, rdev, gettty(rdev)); # endif if(major(rdev) == pty_major && Master(rdev) == True) { /* got a master pty file descriptor */ /* get slot in tty table */ k = minor(rdev) - PTYCNT; tp = &pts_tty[k]; /* ok */ # ifdef DEBUGB eprintf("select: mstr min=%d cnt=%d,%d\n", k, tp->t_tbuf.c_count, tp->t_outq.c_cc); # endif /* check buffers */ if(tp->t_outq.c_cc || tp->t_tbuf.c_count) { /* ok to read */ cnt++; } else { short s=spl7(); /* protect pty_proc */ if (pty_proc[k]) if (pty_proc[k]!=(struct proc *) -1L && pty_proc[k]->p_wchan == (caddr_t) se_register) pty_proc[k] = NULL; else pty_proc[k] = u.u_procp; rds &= ~mask; splx(s); } } else if((tp = gettty(rdev)) != NULL) { /* got a tty file descriptor */ /* check buffers */ # ifdef DEBUGA eprintf("select: tty rdev=%x cnt=%d,%d\n", rdev, tp->t_rawq.c_cc, tp->t_canq.c_cc); # endif if(tp->t_rawq.c_cc || tp->t_canq.c_cc) cnt++; else { short s=spl7(); /* protect SELPROC */ rds &= ~mask; if (SELPROC(tp)) if (SELPROC(tp) != (struct proc *) -1L && SELPROC(tp)->p_wchan == (caddr_t) ldmisc[SEL_REGISTER]) SELPROC(tp) = NULL; else /* no collision */ SELPROC(tp) = u.u_procp; splx(s); } } #ifdef NOT_WORKING /* this can't possibly work! */ /* here we have named pipes */ else if(ip->i_mode & IFIFO) { /* if i_count == 1 no opens left * we notify select of this */ if (ip->i_count == 1) cnt++; else if (ip->i_fwptr) cnt++; else rds &= ~mask; } #endif /*NOT_WORKING*/ /* else check to see if a driver has registerd itself * to provide select for this major number */ else if (poll_table[major(rdev)]!=NULL) { if (!poll_table[major(rdev)](fp,FREAD)) rds &= ~mask; else cnt++; } else { /* Don't know about this device */ rds &= ~mask; } } else {/* invalid fd */ /* should set u.u_error here */ rds &= ~mask; } } } } s = spl7(); /* begin critical section */ if(cnt || u.u_procp->p_flag & STIMO || ! tim) { u.u_rval1 = cnt; if (uap->readfds) suword(uap->readfds, rds); /* copy rds back to user*/ if ( uap->timeout ) untimeout(timout); splx(s); return; } if (! (u.u_procp->p_flag & SSEL)) { splx(s); goto poll; /* poll again if we had i/o while polling */ } /* sleep until timeout or device activity */ # ifdef DEBUG eprintf("select: going to sleep\n"); # endif sleep( (caddr_t) ldmisc[SEL_REGISTER], PZERO+1 ); splx(s); /* end critical section */ /* check for activity while we were asleep */ goto poll; /* poll again */ } /* unselect is called when the select timer expires */ void unselect(p) register struct proc *p; { # ifdef DEBUGA eprintf("select: timed out\n"); # endif /* set select_timed_out process flag*/ p->p_flag |= STIMO; selwakeup(p); } /* Call with p = NULL if collision */ void selwakeup(p) register struct proc *p; { int s = spl7(); if (p) { if (p->p_wchan == (caddr_t) ldmisc[SEL_REGISTER]) { # ifdef DEBUG eprintf("select: in selwakeup p->p_stat = %x\n", p->p_stat); # endif if (p->p_stat == SSLEEP) setrun(p); else unsleep(p); } else if (p->p_flag & SSEL) p->p_flag &= ~SSEL; /* clear selecting flag for this process */ } else { register struct proc *procp; register int i; # ifdef DEBUGD eprintf("select: calling wakeup\n"); # endif /* collision, clear all selecting flags */ procp = proc; for (i = 1; i < v.v_proc; i++, procp ++) procp->p_flag &= ~SSEL; wakeup((caddr_t) ldmisc[SEL_REGISTER]); } splx(s); } @//E*O*F uipc/src/s.c// chmod u=rw,g=rw,o=rw uipc/src/s.c echo x - uipc/src/select.c sed 's/^@//' > "uipc/src/select.c" <<'@//E*O*F uipc/src/select.c//' /* * syscalls.c - system call kernal interface routines. * * Written by Alex Crain. * Extensivly hacked by Brad Bosch. * * I don't think there is anything left here to which this applies, but... * * This file is based in the Berkeley file uipc_syscalls.c, * but is *not* guarenteed to be in any way compatable. It is * close enough to the Berkeley code that the following applies... * * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided "as is" without express or implied warranty. * */ #include "pty.h" #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/user.h> #include <sys/file.h> #include <sys/buf.h> #include <sys/errno.h> #include <sys/systm.h> #include <sys/tty.h> #include <sys/conf.h> #include <sys/var.h> #include <uipc/mbuf.h> #include <uipc/socket.h> #include <uipc/socketvar.h> #include <uipc/domain.h> #include <uipc/protosw.h> #include <uipc/un.h> #include <uipc/fproto.h> #include <uipc/unpcb.h> #include "select.h" void unselect(); extern int pty_major; /* we will need this in the select loop */ extern int ptystate[]; /* needed to test for slave closed */ extern struct proc *pty_proc[]; /* selecting process for each master */ /* This returns a pointer to the tty structure for a device number. * Returns NULL if unknown or error. This works for tty*, console, and ttyp*. * extern struct tty * gettty(); * The above didn't work for ph*. Have to write our own. See below. */ /* we now sleep on ldmisc[SEL_REGISTER] since this is known to other drivers*/ #ifdef NO_LONGER_NEEDED int so_win_major = 0; /* major device of window */ unsigned int so_win_tty = 0; /* address of wintty */ #endif /*NO_LONGER_NEEDED*/ /* Table of driver's select poll entry points indexed by major number */ static int (*poll_table[NUM_SEL_DRIVERS])(); /* This routine is no longer needed (Yea!) */ sesetup() /* setup variables */ { #ifdef NO_LONGER_NEEDED register struct a { int w_major; unsigned int w_tty; } * uap = (struct a *) u.u_ap; if (suser()) { /* must be root to set this stuff */ so_win_major = uap->w_major; so_win_tty = uap->w_tty; } else u.u_error = EPERM; #endif /*NO_LONGER_NEEDED*/ } extern struct tty *pser_tty[]; /* replacement gettty for broken one in kernel */ struct tty * gettty(dev) dev_t dev; { register int maj, min; maj = major(dev); if (maj >= cdevcnt) return(NULL); min = minor(dev); switch (maj) { case 0: /* tty000 */ /* these are hardcoded in kernel too! */ return (pser_tty[min]); case 8: /* ph* */ return (pser_tty[1]); case 7: /* win* */ if (min < 12) return (&(cdevsw[maj].d_ttys)[min-1]); else return (NULL); default: /* other normal cases */ return (&(cdevsw[maj].d_ttys)[min]); } } void selwakeup(); /* forward reference comming */ /* * This is called by other drivers to register their select routine with us. * We return the address of the routine which the driver should call when i/o * may be possible on a device which is under selection. The driver should * save this address for later use. The address of se_register is stored in * ldmisc[SEL_REGISTER] for reference by other drivers. */ void (*se_register (poll_routine, maj_dev))() int (*poll_routine)(); int maj_dev; { # ifdef DEBUG eprintf("se_register: maj_dev=%d, poll_routine=%x\n", maj_dev, poll_routine); # endif if (maj_dev < NUM_SEL_DRIVERS) poll_table[maj_dev] = poll_routine; return(selwakeup); } /* seselect () /* */ select() { register struct a { int nfds; int *readfds; int *writefds; int *execptfds; struct timeval *timeout; } * uap = (struct a *) u.u_ap; int mask, cnt, tim, timout, rds; int i, j, k, l, s; dev_t rdev; struct timeval utimeout; struct file *fp; struct inode *ip; struct tty *tp; struct socket *so; /* * If timeout specified, convert time to hz and set timer. */ /* select_timed_out = 0; */ u.u_procp->p_flag &= ~STIMO; tim = -1; if ( uap->timeout ) { if (copyin(uap->timeout, &utimeout, sizeof(utimeout))) { u.u_error = EINVAL; return; } tim = utimeout.tv_sec * HZ + utimeout.tv_usec * 6/100000; # ifdef DEBUG eprintf("select: timeout set to %d\n", tim); # endif if (tim) timout = timeout(unselect, u.u_procp, tim); } if (uap->nfds > 32) uap->nfds = 32; # ifdef DEBUG eprintf("select: rds=%x nfds=%d\n", *uap->readfds, uap->nfds); # endif poll: u.u_procp->p_flag |= SSEL; cnt = 0; if(uap->readfds) { /* have readbitmask */ rds = fuword(uap->readfds); for(i=0;i < uap->nfds; i++) { u.u_error = 0; /* reset it */ mask = 1 << i; if(rds & mask) { /* is this one? */ # ifdef DEBUGA eprintf("select: mask=%d getf=%d ofile=%d, i=%d\n", mask, getf(i), u.u_ofile[i], i); # endif /* #ifdef USE_SOCKETS */ /* right after if for rds & mask */ /* here is some code for sockets */ fp = getsock(i); if(fp != 0) { /* valid socket */ so = filesock(fp); j = (SS_CANTRCVMORE | SS_CANTSENDMORE); k = SS_ISCONNECTED; /* first check for closed sockets * closed sockets appear only to have j set */ if((so->so_state & j) == j) { /* socket is close. mark as having * data on it, so a read will fail */ cnt++; } /* next we check for a state of incomming ie * accept needs to be called */ else if ( so->so_qlen ) { cnt++; } /* and this is for regular sockets already * connected */ else if( (so->so_rcv.sb_mb != 0) && (so->so_rcv.sb_cc != 0)) { /* has buffer & has chars */ cnt++; } else { rds &= ~mask; } } else /* #endif /* end of socket stuff */ if((fp = getf(i)) != 0) { /* valid open file */ ip = fp->f_inode; rdev = (dev_t) ip->i_rdev; # ifdef DEBUG eprintf("select: fd=%d dev id=%x tp=%x\n", i, rdev, gettty(rdev)); # endif if(major(rdev) == pty_major && Master(rdev) == True) { /* got a master pty file descriptor */ /* get slot in tty table */ k = minor(rdev) - PTYCNT; tp = &pts_tty[k]; /* ok */ # ifdef DEBUGB eprintf("select: mstr min=%d cnt=%d,%d\n", k, tp->t_tbuf.c_count, tp->t_outq.c_cc); # endif /* check buffers */ if((tp->t_outq.c_cc || tp->t_tbuf.c_count) && !(tp->t_state & TTSTOP) || ptystate[k] & SCLOSED) { /* ok to read */ cnt++; } else { short s=spl7(); /* protect pty_proc */ if (pty_proc[k]) if (pty_proc[k]!=(struct proc *) -1L && pty_proc[k]->p_wchan == (caddr_t) se_register) pty_proc[k] = NULL; else pty_proc[k] = u.u_procp; rds &= ~mask; splx(s); } } else if((tp = gettty(rdev)) != NULL) { /* got a tty file descriptor */ /* check buffers */ # ifdef DEBUGA eprintf("select: tty rdev=%x cnt=%d,%d\n", rdev, tp->t_rawq.c_cc, tp->t_canq.c_cc); # endif if(tp->t_rawq.c_cc || tp->t_canq.c_cc || !(tp->t_state & CARR_ON)) cnt++; else { short s=spl7(); /* protect SELPROC */ rds &= ~mask; if (SELPROC(tp) & 0xffffffL) if ((SELPROC(tp) & 0xffffffL) != 0xffffffL && ((struct proc *)SELPROC(tp))->p_wchan == (caddr_t) ldmisc[SEL_REGISTER]) SELPROC(tp) &= 0xff000000L; /*clear*/ else /* no collision */ SELPROC(tp) = (long) u.u_procp | ((SELPROC(tp) & 0xff000000L)); splx(s); } } #ifdef NOT_WORKING /* this can't possibly work! */ /* here we have pipes */ else if(ip->i_mode & IFIFO) { /* if i_count == 1 no opens left * we notify select of this */ if (ip->i_count == 1) cnt++; else if (ip->i_fwptr) cnt++; else rds &= ~mask; } #endif /*NOT_WORKING*/ /* else check to see if a driver has registerd itself * to provide select for this major number */ else if (poll_table[major(rdev)]!=NULL) { if (!poll_table[major(rdev)](fp,FREAD)) rds &= ~mask; else cnt++; } else { /* Don't know about this device */ rds &= ~mask; } } else {/* invalid fd */ /* should set u.u_error here */ rds &= ~mask; } } } } s = spl7(); /* begin critical section */ if(cnt || u.u_procp->p_flag & STIMO || ! tim) { u.u_rval1 = cnt; if (uap->readfds) suword(uap->readfds, rds); /* copy rds back to user*/ if ( uap->timeout ) untimeout(timout); splx(s); return; } if (! (u.u_procp->p_flag & SSEL)) { splx(s); goto poll; /* poll again if we had i/o while polling */ } /* sleep until timeout or device activity */ # ifdef DEBUG eprintf("select: going to sleep\n"); # endif sleep( (caddr_t) ldmisc[SEL_REGISTER], PZERO+1 ); splx(s); /* end critical section */ /* check for activity while we were asleep */ goto poll; /* poll again */ } /* unselect is called when the select timer expires */ void unselect(p) register struct proc *p; { # ifdef DEBUGA eprintf("select: timed out\n"); # endif /* set select_timed_out process flag*/ p->p_flag |= STIMO; selwakeup(p); } /* Call with p = NULL if collision */ void selwakeup(p) register struct proc *p; { int s = spl7(); if (p) { if (p->p_wchan == (caddr_t) ldmisc[SEL_REGISTER]) { # ifdef DEBUG eprintf("select: in selwakeup p->p_stat = %x\n", p->p_stat); # endif if (p->p_stat == SSLEEP) setrun(p); else unsleep(p); } else if (p->p_flag & SSEL) p->p_flag &= ~SSEL; /* clear selecting flag for this process */ } else { register struct proc *procp; register int i; # ifdef DEBUGD eprintf("select: calling wakeup\n"); # endif /* collision, clear all selecting flags */ procp = proc; for (i = 1; i < v.v_proc; i++, procp ++) procp->p_flag &= ~SSEL; wakeup((caddr_t) ldmisc[SEL_REGISTER]); } splx(s); } @//E*O*F uipc/src/select.c// chmod u=rw,g=rw,o=rw uipc/src/select.c echo x - uipc/src/select.h sed 's/^@//' > "uipc/src/select.h" <<'@//E*O*F uipc/src/select.h//' struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds */ }; /* * Operations on timevals. * * NB: timercmp does not work for >= or <=. */ #define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) #define timercmp(tvp, uvp, cmp) \ ((tvp)->tv_sec cmp (uvp)->tv_sec || \ (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) #define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 /* extra masks for p_flag in proc struct */ #define SSEL 0x400000 /* This process is selecting */ /* #define SELPROC(tp) (*((struct proc **) (& tp->spacer[0]))) */ #define SELPROC(tp) (*((long *) (& tp->spacer[0]))) /* BYE BYE #define select(nfds, reads, writes, excepts, tmout) \ syslocal(19, nfds, reads, writes, excepts, tmout) */ @//E*O*F uipc/src/select.h// chmod u=rw,g=rw,o=rw uipc/src/select.h echo x - uipc/src/slave.side sed 's/^@//' > "uipc/src/slave.side" <<'@//E*O*F uipc/src/slave.side//' }else { /* normal slot */ /* not sure this is right */ k = minor(ip->i_rdev); tp = &pts_tty[k]; /* ok */ } @//E*O*F uipc/src/slave.side// chmod u=rw,g=r,o=r uipc/src/slave.side echo x - uipc/src/socket1.c sed 's/^@//' > "uipc/src/socket1.c" <<'@//E*O*F uipc/src/socket1.c//' /* * socket.c - high level socket routines * * Written by Alex Crain. * * This file is based in the Berkeley file uipc_socket.c, * but is *not* guarenteed to be in any way compatable. It is * close enough to the Berkeley code that the following applies... * * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided "as is" without express or implied warranty. * */ #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/user.h> #include <sys/proc.h> #include <sys/file.h> #include <sys/var.h> #include <sys/errno.h> #include <uipc/mbuf.h> #include <uipc/socket.h> #include <uipc/socketvar.h> #include <uipc/domain.h> #include <uipc/protosw.h> #include <uipc/fproto.h> int socreate (domain, sop, type, proto) int domain; struct socket ** sop; int type, proto; { register struct protosw * prp; struct socket * so; struct mbuf * m; int error = 0; if (proto) prp = pffindproto (domain, proto, type); else prp = pffindtype (domain, type); if (prp == 0) return EPROTONOSUPPORT; if (prp->pr_type != type) return EPROTOTYPE; m = m_getclr (M_WAIT, MT_SOCKET); so = mtod (m, struct socket *); so->so_options = 0; so->so_state = (suser () ? SS_PRIV : 0); so->so_type = type; so->so_proto = prp; if (error = (* prp->pr_usrreq) (so, PRU_ATTACH, (struct mbuf *) 0, (struct mbuf *) proto, (struct mbuf *) 0)) { so->so_state |= SS_NOFDREF; sofree(so); return error; } * sop = so; return 0; } int sobind (so, nam) struct socket * so; struct mbuf * nam; { int s = splnet (); int error = (* so->so_proto->pr_usrreq) (so, PRU_BIND, (struct mbuf *) 0, nam, (struct mbuf *) 0); splx (s); return error; } int solisten (so, backlog) struct socket * so; int backlog; { int s = splnet (); int error; if (error = (* so->so_proto->pr_usrreq) (so, PRU_LISTEN, (struct mbuf *) 0, (struct mbuf *) 0, (struct mbuf *) 0)) goto bad; if (so->so_q == 0) { so->so_q = so; so->so_q0 = so; so->so_options |= SO_ACCEPTCONN; } if (backlog < 0) backlog = 0; so->so_qlimit = MIN (backlog, SOMAXCONN); bad: splx (s); return error; } void sofree (so) struct socket * so; { if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) return; if (so->so_head) { if (! soqremque (so, 0) && ! soqremque (so, 1)) panic ("sofree dq"); so->so_head = 0; } sbrelease (&so->so_snd); sorflush (so); (void) m_free (dtom (so)); } int soclose (so) struct socket * so; { int s = splnet (); int error = 0; if (so->so_options & SO_ACCEPTCONN) { while (so->so_q0 != so) (void) soabort (so->so_q0); while (so->so_q != so) (void) soabort (so->so_q); } if (so->so_pcb == 0) goto discard; if (so->so_state & SS_ISCONNECTED) { if ((so->so_state & SS_ISDISCONNECTING) == 0) if (error = sodisconnect (so)) goto drop; if (so->so_options & SO_LINGER) { if ((so->so_state & SS_ISDISCONNECTING) && (so->so_state & SS_NBIO)) goto drop; while (so->so_state & SS_ISCONNECTED) (void) sleep ((caddr_t) &so->so_timeo, PZERO + 1); } } drop: if (so->so_pcb) { int error2 = (* so->so_proto->pr_usrreq) (so, PRU_DETACH, (struct mbuf *) 0, (struct mbuf *) 0, (struct mbuf *) 0); if (error == 0) error = error2; } discard: if (so->so_state & SS_NOFDREF) panic ("soclose: NODEREF"); so->so_state |= SS_NOFDREF; sofree (so); splx (s); return error; } int soabort (so) struct socket * so; { return (* so->so_proto->pr_usrreq) (so, PRU_ABORT, (struct mbuf *) 0, (struct mbuf *) 0, (struct mbuf *) 0); } int soaccept (so, nam) struct socket * so; struct mbuf * nam; { int s = splnet (); int error; if ((so->so_state & SS_NOFDREF) == 0) panic ("soaccept: !NOFDREF"); so->so_state &= ~SS_NOFDREF; error = (* so->so_proto->pr_usrreq) (so, PRU_ACCEPT, (struct mbuf *) 0, nam, (struct mbuf *) 0); splx (s); return (error); } int soconnect (so, nam) struct socket * so; struct mbuf * nam; { int s; int error; if (so->so_options & SO_ACCEPTCONN) return EOPNOTSUPP; s = splnet (); if (so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING) && ((so->so_proto->pr_flags & PR_CONNREQUIRED) || (error = sodisconnect (so)))) error = EISCONN; else error = (* so->so_proto->pr_usrreq) (so, PRU_CONNECT, (struct mbuf *) 0, nam, (struct mbuf *) 0); splx (s); return error; } int soconnect2 (so1, so2) struct socket * so1, * so2; { int s = splnet (); int error = (* so1->so_proto->pr_usrreq) (so1, PRU_CONNECT2, (struct mbuf *) 0, (struct mbuf *) so2, (struct mbuf *) 0); splx (s); return error; } int sodisconnect (so) struct socket * so; { int s = splnet (); int error; if ((so->so_state & SS_ISCONNECTED) == 0) { error = ENOTCONN; goto bad; } if (so->so_state & SS_ISDISCONNECTING) { error = EALREADY; goto bad; } error = (* so->so_proto->pr_usrreq) (so, PRU_DISCONNECT, (struct mbuf *) 0, (struct mbuf *) 0, (struct mbuf *) 0); bad: splx (s); return error; } int sosend (so, nam, flags, rights) struct socket * so; struct mbuf * nam; int flags; struct mbuf * rights; { int space, s, rlen = 0, dontroute; int len, error = 0, first = 1; struct mbuf ** mb, * top = 0, * m; /* * barf if we want to send one big chunk and don't have the space. */ if (sendallatonce (so) && u.u_count > so->so_snd.sb_hiwat) return (EMSGSIZE); dontroute = (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && (so->so_proto->pr_flags & PR_ATOMIC); if (rights) rlen = rights->m_len; #define snderr(errno) { error = errno; splx (s); goto release; } restart: sblock (&so->so_snd); do { s = splnet (); /* check out our basic requirements. */ if (so->so_state & SS_CANTSENDMORE) snderr (EPIPE); if (so->so_error) { error = so->so_error; so->so_error = 0; splx (s); goto release; } if ((so->so_state & SS_ISCONNECTED) == 0) { if (so->so_proto->pr_flags & PR_CONNREQUIRED) snderr (ENOTCONN); if (nam == 0) snderr (EDESTADDRREQ); } if (flags & MSG_OOB) space = 1024; else { space = sbspace (&so->so_snd); /* * If we need more room, wait for it. */ if (space <= rlen || sendallatonce (so) && space < u.u_count + rlen) { if (so->so_state & SS_NBIO) { if (first) error = EWOULDBLOCK; splx (s); goto release; } sbunlock (&so->so_snd); sbwait (&so->so_snd); splx (s); goto restart; } } splx (s); /* * We have the room, we've done sanity checks. * Now make an mbuf chain out of our data, waiting if necessarry. */ mb = ⊤ space -= rlen; while (space > 0 && u.u_count) { MGET (m, M_WAIT, MT_DATA); len = MIN (MIN (MLEN, u.u_count), space); space -= len; iomove (mtod (m, caddr_t), len, IO_WRITE); m->m_len = len; * mb = m; if (error = u.u_error) goto release; mb = &m->m_next; #ifdef DEBUG dump_mbuf(m,"sosendit"); #endif } if (dontroute) so->so_options |= SO_DONTROUTE; /* * write mbuf to socket. */ s = splnet (); error = (* so->so_proto->pr_usrreq) (so, (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, top, (caddr_t) nam, rights); splx (s); if (dontroute) so->so_options &= ~SO_DONTROUTE; rights = top = (struct mbuf *) 0; rlen = first = 0; } while (error == 0 && u.u_count); release: sbunlock (&so->so_snd); #ifdef SELECT selwakeup(0); /* let us look at all, just so I don't have to go * looking, I know, I am lazy */ #endif if (top) m_freem (top); if (error == EPIPE) psignal (u.u_procp, SIGPIPE); return error; } int soreceive (so, nam, flags, rights) struct socket * so; struct mbuf ** nam; int flags; struct mbuf ** rights; { struct mbuf * m, * nextrecord; int len, error = 0, s, moff, offset; struct protosw * pr = so->so_proto; if (rights) * rights = (struct mbuf *) 0; /* if we have a rights, zero it */ if (nam) * nam = (struct mbuf *) 0; /* zero from buffer address */ if (flags & MSG_OOB) { m = m_get (M_WAIT, MT_DATA); if (error = (* pr->pr_usrreq) (so, PRU_RCVOOB, m, (struct mbuf *) (flags & MSG_PEEK), (struct mbuf *) 0)) goto bad; do { len = MIN (u.u_count, m->m_len); iomove (mtod (m, caddr_t), len, IO_READ); m = m_free (m); } while (u.u_count && (error = u.u_error) == 0 && m); bad: if (m) m_freem (m); return error; } #ifdef DEBUG dump_mbuf (dtom (so),"sorecieve"); #endif restart: sblock (&so->so_rcv); s = splnet (); if (so->so_rcv.sb_cc == 0) /* if there is no chars in buffer */ { if (so->so_error) /* if there is an error affecting connection */ { error = so->so_error; so->so_error = 0; goto release; } /* if ((so->so_state & SS_ISCONNECTED) == 0 && (pr->pr_flags & PR_CONNREQUIRED)) { error = ENOTCONN; goto release; } */ if (so->so_state & SS_CANTRCVMORE || u.u_count == 0) goto release; if (so->so_state & SS_NBIO) /* if nonblocking return EWOULDBLOCK */ { error = EWOULDBLOCK; goto release; } sbunlock (&so->so_rcv); sbwait (&so->so_rcv); splx (s); goto restart; } /* this checks the mbuf chain to see if there is data */ if ((m = so->so_rcv.sb_mb) == (struct mbuf *) 0) panic ("receive 1"); nextrecord = m->m_act; if (pr->pr_flags & PR_ADDR) { if (m->m_type != MT_SONAME) panic ("receive 1a"); if (flags & MSG_PEEK) { if (nam) * nam = m_copy (m, 0, m->m_len); m = m->m_next; } else { sbfree (&so->so_rcv, m); if (nam) { * nam = m; m = m->m_next; (* nam)->m_next = (struct mbuf *) 0; so->so_rcv.sb_mb = m; } else { MFREE (m, so->so_rcv.sb_mb); m = so->so_rcv.sb_mb; } if (m) m->m_act = nextrecord; } } if (m && m->m_type == MT_RIGHTS) { if ((pr->pr_flags & PR_RIGHTS) == 0) panic ("receive 2"); if (flags & MSG_PEEK) { if (rights) * rights = m_copy (m, 0, m->m_len); m = m->m_next; } else { sbfree (&so->so_rcv, m); if (rights) { * rights = m; so->so_rcv.sb_mb = m->m_next; m->m_next = (struct mbuf *) 0; m = so->so_rcv.sb_mb; } else { MFREE (m, so->so_rcv.sb_mb); m = so->so_rcv.sb_mb; } if (m) m->m_act = nextrecord; } } moff = 0; offset = 0; while (m && u.u_count != 0 && error == 0) { if (m->m_type != MT_DATA && m->m_type != MT_HEADER) panic ("receive 3"); len = u.u_count; so->so_state &= ~SS_RCVATMARK; if (so->so_oobmark && len > so->so_oobmark - offset) len = so->so_oobmark - offset; if (len > m->m_len - moff) len = m->m_len - moff; splx (s); iomove (mtod (m, caddr_t) + moff, (int) len, IO_READ); error = u.u_error; s = splnet (); if (len == m->m_len - moff) { if (flags & MSG_PEEK) { m = m->m_next; moff = 0; } else { nextrecord = m->m_act; sbfree (&so->so_rcv, m); MFREE (m, so->so_rcv.sb_mb); if (m = so->so_rcv.sb_mb) m->m_act = nextrecord; } } else { if (flags & MSG_PEEK) moff += len; else { m->m_off += len; m->m_len -= len; so->so_rcv.sb_cc -= len; } } if (so->so_oobmark) { if ((flags & MSG_PEEK) == 0) { so->so_oobmark -= len; if (so->so_oobmark == 0) { so->so_state |= SS_RCVATMARK; break; } } else offset += len; } } if ((flags & MSG_PEEK) == 0) { if (m == 0) so->so_rcv.sb_mb = nextrecord; else if (pr->pr_flags & PR_ATOMIC) (void) sbdroprecord (&so->so_rcv); if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) (* pr->pr_usrreq) (so, PRU_RCVD, (struct mbuf *) 0, (struct mbuf *) 0, (struct mbuf *) 0); if (error == 0 && rights && * rights && pr->pr_domain->dom_externalize) error = (* pr->pr_domain->dom_externalize) (* rights); } release: sbunlock (&so->so_rcv); splx (s); return error; } void sorflush (so) struct socket * so; { struct sockbuf * sb = &so->so_rcv; struct protosw * pr = so->so_proto; int s; struct sockbuf asb; sblock (sb); s = splimp (); socantrcvmore (so); sbunlock (sb); #ifdef SELECT selwakeup(0); #endif asb = * sb; bzero ((caddr_t) sb, sizeof (* sb)); splx (s); if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) (* pr->pr_domain->dom_dispose) (asb.sb_mb); sbrelease (&asb); } int sosetopt (so, level, optname, m0) struct socket * so; int level, optname; struct mbuf * m0; { int error = 0; struct mbuf * m = m0; if (level != SOL_SOCKET) { if (so->so_proto && so->so_proto->pr_ctloutput) return (* so->so_proto->pr_ctloutput) (PRCO_SETOPT, so, level, optname, &m0); error = ENOPROTOOPT; } else { switch (optname) { case SO_LINGER: if (m == NULL || m->m_len != sizeof (struct linger)) { error = EINVAL; goto bad; } so->so_linger = mtod (m, struct linger *)->l_linger; /* fall through ... */ case SO_DEBUG: case SO_KEEPALIVE: case SO_DONTROUTE: case SO_USELOOPBACK: case SO_BROADCAST: case SO_REUSEADDR: case SO_OOBINLINE: if (m == (struct mbuf *) 0 || m->m_len < sizeof (int)) { error = EINVAL; goto bad; } if (* mtod (m, int *)) so->so_options |= optname; else so->so_options &= ~optname; break; case SO_SNDBUF: case SO_RCVBUF: case SO_SNDLOWAT: case SO_RCVLOWAT: case SO_SNDTIMEO: case SO_RCVTIMEO: if (m == (struct mbuf *) 0 || m->m_len < sizeof (int)) { error = EINVAL; goto bad; } switch (optname) { case SO_SNDBUF: if (sbreserve (&so->so_rcv, * mtod (m, int *)) == 0) { error = ENOBUFS; goto bad; } break; case SO_RCVBUF: if (sbreserve (&so->so_rcv, * mtod (m, int *)) == 0) { error = ENOBUFS; goto bad; } break; case SO_SNDLOWAT: so->so_snd.sb_lowat = * mtod (m, int *); break; case SO_RCVLOWAT: so->so_rcv.sb_lowat = * mtod (m, int *); break; case SO_SNDTIMEO: so->so_snd.sb_timeo = * mtod (m, int *); break; case SO_RCVTIMEO: so->so_rcv.sb_timeo = * mtod (m, int *); break; } break; default: error = ENOPROTOOPT; break; } } bad: if (m) (void) m_free (m); return error; } int sogetopt (so, level, optname, mp) struct socket * so; int level, optname; struct mbuf ** mp; { struct mbuf * m; if (level != SOL_SOCKET) { if (so->so_proto && so->so_proto->pr_ctloutput) return (* so->so_proto->pr_ctloutput) (PRCO_GETOPT, so, level, optname, mp); else return ENOPROTOOPT; } else { m = m_get (M_WAIT, MT_SOOPTS); m->m_len = sizeof (int); switch (optname) { case SO_LINGER: m->m_len = sizeof (struct linger); mtod (m, struct linger *)->l_onoff = so->so_options & SO_LINGER; mtod (m, struct linger *)->l_linger = so->so_linger; break; case SO_DEBUG: case SO_KEEPALIVE: case SO_DONTROUTE: case SO_USELOOPBACK: case SO_BROADCAST: case SO_REUSEADDR: case SO_OOBINLINE: * mtod (m, int *) = so->so_options & optname; break; case SO_TYPE: * mtod (m, int *) = so->so_type; break; case SO_ERROR: * mtod (m, int *) = so->so_error; break; case SO_SNDBUF: * mtod (m, int *) = so->so_snd.sb_hiwat; break; case SO_RCVBUF: * mtod (m, int *) = so->so_rcv.sb_hiwat; break; case SO_SNDLOWAT: * mtod (m, int *) = so->so_snd.sb_lowat; break; case SO_RCVLOWAT: * mtod (m, int *) = so->so_rcv.sb_lowat; break; case SO_SNDTIMEO: * mtod (m, int *) = so->so_snd.sb_timeo; break; case SO_RCVTIMEO: * mtod (m, int *) = so->so_rcv.sb_timeo; break; default: (void) m_free (m); return ENOPROTOOPT; } * mp = m; return 0; } } void sohasoutofband (so) struct socket * so; { struct proc * p; if (so->so_pgrp < 0) signal (-so->so_pgrp, SIGURG); else if (so->so_pgrp) for (p = proc; p < (struct proc *) v.ve_proc; p = p->p_xlink) if (p->p_pid == so->so_pgrp) { psignal (p, SIGURG); break; } #ifdef SB_COLL if (so->so_rcv.sb_sel) { selwakeup (so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); so->so_rcv,sb_sel = 0; so->so_rcv.sb_flags &= ~SB_COLL; } #endif } @//E*O*F uipc/src/socket1.c// chmod u=rw,g=r,o=r uipc/src/socket1.c echo x - uipc/src/socket2.c sed 's/^@//' > "uipc/src/socket2.c" <<'@//E*O*F uipc/src/socket2.c//' #ifndef LINT static char * sccsdef = "%W% %D%"; #endif /* * socket2.c - low level socket routines * * Written by Alex Crain. * * This file is based in the Berkeley file uipc_socket2.c, * but is *not* guarenteed to be in any way compatable. It is * close enough to the Berkeley code that the following applies... * * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided "as is" without express or implied warranty. * */ #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/errno.h> #include <sys/proc.h> #include <sys/var.h> #include <uipc/mbuf.h> #include <uipc/socket.h> #include <uipc/socketvar.h> #include <uipc/protosw.h> #include <uipc/domain.h> #include <uipc/fproto.h> void soisconnecting (so) struct socket * so; { so->so_state &= ~(SS_ISCONNECTED | SS_ISDISCONNECTING); so->so_state |= SS_ISCONNECTING; wakeup ((caddr_t) &so->so_timeo); } void soisconnected (so) struct socket * so; { struct socket * head = so->so_head; if (head) { if (soqremque (so, 0) == 0) panic ("soisconnected"); soinsque (head, so, 1); sorwakeup (head); wakeup ((caddr_t) &head->so_timeo); } so->so_state &= ~(SS_ISCONNECTING | SS_ISDISCONNECTING); so->so_state |= SS_ISCONNECTED; wakeup ((caddr_t) &so->so_timeo); sorwakeup (so); sowwakeup (so); } void soisdisconnecting (so) struct socket * so; { so->so_state &= ~SS_ISCONNECTING; so->so_state |= (SS_ISDISCONNECTING | SS_CANTRCVMORE | SS_CANTSENDMORE); wakeup ((caddr_t) &so->so_timeo); sorwakeup (so); sowwakeup (so); } void soisdisconnected (so) struct socket * so; { so->so_state &= ~(SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING); so->so_state |= (SS_CANTRCVMORE | SS_CANTSENDMORE); wakeup ((caddr_t) &so->so_timeo); sorwakeup (so); sowwakeup (so); } struct socket * sonewconn (head) struct socket * head; { struct socket * so; struct mbuf * m; if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2) goto bad; if ((m = m_getclr(M_DONTWAIT, MT_SOCKET)) == (struct mbuf *) 0) goto bad; so = mtod (m, struct socket *); so->so_type = head->so_type; so->so_options = head->so_options & ~SO_ACCEPTCONN; so->so_linger = head->so_linger; so->so_state = head->so_state | SS_NOFDREF; so->so_proto = head->so_proto; so->so_timeo = head->so_timeo; so->so_pgrp = head->so_pgrp; soinsque (head, so, 0); if ((* so->so_proto->pr_usrreq) (so, PRU_ATTACH, (struct mbuf *) 0, (struct mbuf *) 0, (struct mbuf *) 0)) { (void) soqremque (so, 0); (void) m_free (m); goto bad; } return (so); bad: return (struct socket *) 0; } void soinsque (head, so, q) struct socket * head, * so; int q; { so->so_head = head; if (q == 0) { head->so_q0len++; so->so_q0 = head->so_q0; head->so_q0 = so; } else { head->so_qlen++; so->so_q = head->so_q; head->so_q = so; } } int soqremque (so, q) struct socket * so; int q; { struct socket * head, * prev, * next; head = so->so_head; prev = head; for (;;) { next = q ? prev->so_q : prev->so_q0; if (next == so) break; if (next == head) return 0; prev = next; } if (q == 0) { prev->so_q0 = next->so_q0; head->so_q0len--; } else { prev->so_q = next->so_q; head->so_qlen--; } next->so_q0 = next->so_q = 0; next->so_head = 0; return 1; } void socantsendmore (so) struct socket * so; { so->so_state |= SS_CANTSENDMORE; sowwakeup (so); } void socantrcvmore (so) struct socket * so; { so->so_state |= SS_CANTRCVMORE; sorwakeup (so); } #ifdef SB_COLL void sbselqueue (sb) struct sockbuf * sb; { struct proc * p; if ((p = sb->sb_sel) && p->p_wchan == (caddr_t) &selwait) sb->sb_flags |= SB_COLL; else sb->sb_sel = u.u_procp; } #endif void sbwait (sb) struct sockbuf * sb; { sb->sb_flags |= SB_WAIT; (void) sleep ((caddr_t) &sb->sb_cc, PZERO + 1); } void sbwakeup (sb) struct sockbuf * sb; { #ifdef SB_COLL if (sb->sb_sel) { selwakeup (sb->sb_sel, sb->sb_flags & SB_COLL); sb->sb_sel = 0; sb->sb_flags &= ~SB_COLL; } #endif if (sb->sb_flags & SB_WAIT) { sb->sb_flags &= ~SB_WAIT; wakeup ((caddr_t) &sb->sb_cc); } } /* ARGSUSED */ void sowakeup (so, sb) struct socket * so; struct sockbuf * sb; { struct proc * p; sbwakeup (sb); if (so->so_state & SS_ASYNC) { if (so->so_pgrp < 0) signal (-so->so_pgrp, SIGIO); else if (so->so_pgrp) for (p = proc; p < (struct proc *) v.ve_proc; p = p->p_xlink) if (p->p_pid == so->so_pgrp) { psignal (p, SIGURG); break; } } } /* * Socket buffer utiliy routines. */ int soreserve (so, sndcc, rcvcc) struct socket * so; int sndcc, rcvcc; { if (sbreserve (&so->so_snd, sndcc) == 0) goto bad1; if (sbreserve (&so->so_rcv, rcvcc) == 0) goto bad2; return 0; bad2: sbrelease (&so->so_snd); bad1: return ENOBUFS; } /* * Reserve mbufs for a socketbuf. */ int sbreserve (sb, cc) struct sockbuf * sb; { sb->sb_hiwat = cc; sb->sb_mbmax = cc * 2; return 1; } void sbrelease (sb) struct sockbuf * sb; { sbflush (sb); sb->sb_hiwat = sb->sb_mbmax = 0; } void sbappend (sb, m) struct sockbuf * sb; struct mbuf * m; { struct mbuf * n; if (m == 0) return; if (n = sb->sb_mb) { while (n->m_act) n = n->m_act; while (n->m_next) n = n->m_next; } sbcompress (sb, m, n); } void sbappendrecord (sb, m0) struct sockbuf * sb; struct mbuf * m0; { struct mbuf * m; if (m0 == 0) return; if (m = sb->sb_mb) while (m->m_act) m = m->m_act; sballoc (sb, m0); if (m) m->m_act = m0; else sb->sb_mb = m0; m = m0->m_next; m0->m_next = 0; sbcompress (sb, m, m0); } int sbappendaddr (sb, asa, m0, rights0) struct sockbuf * sb; struct sockaddr * asa; struct mbuf * rights0, * m0; { struct mbuf * m, * n; int space = sizeof (* asa); for (m = m0; m; m = m->m_next) space += m->m_len; if (rights0) space += rights0->m_len; if (space > sbspace (sb)) return 0; MGET (m, M_DONTWAIT, MT_SONAME); if (m == 0) return 0; * mtod (m, struct sockaddr *) = * asa; m->m_len = sizeof (* asa); if (rights0 && rights0->m_len) { if ((m->m_next = m_copy (rights0, 0, rights0->m_len)) == 0) { m_freem (m); return 0; } sballoc (sb, m->m_next); } sballoc (sb, m); if (n = sb->sb_mb) { while (n->m_act) n = n->m_act; n->m_act = m; } else sb->sb_mb = m; if (m->m_next) m = m->m_next; if (m0) sbcompress (sb, m0, m); return 1; } int sbappendrights (sb, m0, rights) struct sockbuf * sb; struct mbuf * rights, * m0; { struct mbuf * m, * n; int space = 0; if (rights == 0) panic ("sbappendrights"); for (m = m0; m; m = m->m_next) space += m->m_len; space += rights->m_len; if (space > sbspace (sb)) return 0; if ((m = m_copy (rights, 0, rights->m_len)) == 0) return 0; sballoc (sb, m); if (n = sb->sb_mb) { while (n->m_act) n = n->m_act; n->m_act = m; } else sb->sb_mb = m; if (m0) sbcompress (sb, m0, m); return 1; } void sbcompress (sb, m, n) struct sockbuf * sb; struct mbuf * m, * n; { while (m) { if (m->m_len == 0) { m = m_free (m); continue; } if (n && n->m_off <= MMAXOFF && m->m_off <= MMAXOFF && (n->m_off + n->m_len + m->m_len <= MMAXOFF && n->m_type == m->m_type)) { bcopy (mtod (m, caddr_t), mtod (n, caddr_t) + n->m_len, (unsigned) m->m_len); n->m_len += m->m_len; sb->sb_cc += m->m_len; m = m_free (m); continue; } sballoc (sb, m); if (n) n->m_next = m; else sb->sb_mb = m; n = m; m = m->m_next; n->m_next = 0; } } void sbflush (sb) struct sockbuf * sb; { if (sb->sb_flags & SB_LOCK) panic ("sbflush"); while (sb->sb_mbcnt) sbdrop (sb, (int) sb->sb_cc); if (sb->sb_cc || sb->sb_mbcnt || sb->sb_mb) panic ("sbflush 2"); } /* * Throw away len bytes from sb, starting at the beginning. */ void sbdrop (sb, len) struct sockbuf * sb; int len; { register struct mbuf * m, * mn; struct mbuf * next; next = (m = sb->sb_mb) ? m->m_act : 0; while (len > 0) { if (m == 0) { if (next == 0) panic ("sbdrop"); m = next; next = m->m_act; continue; } if (m->m_len > len) { m->m_len -= len; m->m_off += len; sb->sb_cc -= len; break; } len -= m->m_len; sbfree (sb, m); MFREE (m, mn); m = mn; } while (m && m->m_len == 0) /* when is this case necessary? */ { sbfree (sb, m); MFREE (m, mn); m = mn; } if (m) { sb->sb_mb = m; m->m_act = next; } else sb->sb_mb = next; } void sbdroprecord (sb) struct sockbuf * sb; { struct mbuf * m, * mn; m = sb->sb_mb; if (m) { sb->sb_mb = m->m_act; do { sbfree (sb, m); MFREE (m, mn); } while (m - mn); } } @//E*O*F uipc/src/socket2.c// chmod u=rw,g=r,o=r uipc/src/socket2.c echo x - uipc/src/syscalls.c sed 's/^@//' > "uipc/src/syscalls.c" <<'@//E*O*F uipc/src/syscalls.c//' /* * syscalls.c - system call kernal interface routines. * * Written by Alex Crain. * * This file is based in the Berkeley file uipc_syscalls.c, * but is *not* guarenteed to be in any way compatable. It is * close enough to the Berkeley code that the following applies... * * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided "as is" without express or implied warranty. * */ #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/user.h> #include <sys/file.h> #include <sys/buf.h> #include <sys/errno.h> #include <sys/systm.h> #include <sys/tty.h> #include <uipc/mbuf.h> #include <uipc/socket.h> #include <uipc/socketvar.h> #include <uipc/domain.h> #include <uipc/protosw.h> #include <uipc/un.h> #include <uipc/fproto.h> #include <uipc/unpcb.h> struct file * getsock (); /* * socket (domain, type, protocol) * * Create a socket and add it to the processes open file table. This involves * some creativity, because the file structure is really too small for our * uses. The kernal only knows about inodes, so there is no f_type slot. * Instead, the kernal looks for a NULL f_inode, which means that we are a * socket. Unfortunately, this means that there is no room in the file * structure for the socket address, so we keep all of our sockets in a linear * table, and store the table offset in f_offset, which has no meaning here * anyway. (see the macros filesock() and sockoffet() in conf.h). */ socket () { register struct a { int domain; int type; int proto; } * uap = (struct a *) u.u_ap; struct socket * so; struct file *fp; if ((fp = falloc ((struct inode *) 0, FREAD| FWRITE)) == NULL) return; if (u.u_error = socreate (uap->domain, &so, uap->type, uap->proto)) goto bad; fp->f_offset = sockoffset (so); return; bad: u.u_ofile[u.u_rval1] = 0; fp->f_count = 0; fp->f_next = ffreelist; ffreelist = fp; } bind () { struct a { int s; caddr_t name; int namelen; } * uap = (struct a *) u.u_ap; struct file * fp; struct mbuf * nam; if ((fp = getsock (uap->s)) == 0) return; if (u.u_error = sockargs (&nam, uap->name, uap->namelen, MT_SONAME)) return; u.u_error = sobind (filesock (fp), nam); m_freem (nam); } listen () { struct a { int s; int backlog; } * uap = (struct a *) u.u_ap; struct file * fp; if ((fp = getsock (uap->s)) == 0) return; u.u_error = solisten (filesock (fp), uap->backlog); } accept () { struct a { int s; caddr_t name; int * anamelen; } * uap = (struct a *) u.u_ap; struct file * fp; struct mbuf * nam; int namelen; int s; struct socket * so; if (uap->name == 0) goto noname; if (u.u_error = copyin ((caddr_t) uap->anamelen, (caddr_t) &namelen, sizeof (namelen))) return; if (useracc ((caddr_t) uap->name, (u_int) namelen, UACC_WRITE) == 0) { u.u_error = EFAULT; return; } noname: if ((fp = getsock (uap->s)) == 0) return; s = splnet (); so = filesock (fp); if ((so->so_options & SO_ACCEPTCONN) == 0) { u.u_error = EINVAL; goto bad; } if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { u.u_error = EWOULDBLOCK; goto bad; } while (so->so_qlen == 0 && so->so_error == 0) { if (so->so_state & SS_CANTRCVMORE) { so->so_error = ECONNABORTED; break; } sleep ((caddr_t) &so->so_timeo, PZERO+1); } if (so->so_error) { u.u_error = so->so_error; so->so_error = 0; goto bad; } if ((fp = falloc ((struct inode *) 0, FREAD| FWRITE)) == 0) goto bad; else { struct socket * so2 = so->so_q; if (soqremque (so2, 1) == 0) panic ("accept"); so = so2; } fp->f_offset = sockoffset (so); nam = m_get (M_WAIT, MT_SONAME); (void) soaccept (so, nam); if (uap->name) { if (namelen > nam->m_len) namelen = nam->m_len; (void) copyout (mtod (nam, caddr_t), (caddr_t) uap->name, (u_int) namelen); (void) copyout ((caddr_t) &namelen, (caddr_t) uap->anamelen, sizeof (*uap->anamelen)); } m_freem (nam); bad: splx (s); return; } connect () { struct a { int s; caddr_t name; int namelen; } * uap = (struct a *) u.u_ap; struct file * fp; struct socket * so; struct mbuf * nam; int s; if ((fp = getsock (uap->s)) == 0) return; so = filesock (fp); if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { u.u_error = EALREADY; return; } if (u.u_error = sockargs (&nam, uap->name, uap->namelen, MT_SONAME)) return; if (u.u_error = soconnect (so, nam)) goto bad; if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { u.u_error = EINPROGRESS; m_freem (nam); return; } s = splnet (); if (setjmp (u.u_qsav)) { if (u.u_error == 0) u.u_error = EINTR; goto bad2; } while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) sleep ((caddr_t) &so->so_timeo, PZERO + 1); u.u_error = so->so_error; so->so_error = 0; bad2: splx (s); bad: so->so_state &= ~SS_ISCONNECTING; m_freem (nam); } socketpair () { struct a { int domain; int type; int proto; int * rsv; } * uap = (struct a *) u.u_ap; register struct file * fp1, * fp2; struct socket * so1, * so2; int sv[2]; /* * verify that uap->rsv is in the users address space & writeable. * UACC_READ and UACC_WRITE are defined in <uipc/conf.h>. */ if (useracc ((caddr_t) uap->rsv, sizeof (int) * 2, UACC_WRITE) == 0) { u.u_error = EFAULT; return; } /* * Create some sockets (2). */ if (u.u_error = socreate (uap->domain, &so1, uap->type, uap->proto)) return; if (u.u_error = socreate (uap->domain, &so2, uap->type, uap->proto)) goto free1; /* * assign them to file structures in the open file table. */ if ((fp1 = falloc ((struct inode *) 0, FREAD | FWRITE)) == NULL) goto free2; sv[0] = u.u_rval1; fp1->f_offset = sockoffset (so1); if ((fp2 = falloc ((struct inode *) 0, FREAD | FWRITE)) == NULL) goto free3; sv[1] = u.u_rval1; fp2->f_offset = sockoffset (so2); /* * Connect them together. */ if (u.u_error = soconnect2 (so1, so2)) goto free4; /* * DATAGRAMS need to be connected both ways */ if (uap->type == SOCK_DGRAM) if (u.u_error = soconnect2 (so2, so1)) goto free4; /* * done, return 0 and pass the file descriptors back. */ u.u_rval1 = 0; copyout ((caddr_t) sv, (caddr_t) uap->rsv, 2 * sizeof (int)); return; free4: fp2->f_count = 0; fp2->f_next = ffreelist; ffreelist = fp2; free3: fp1->f_count = 0; fp1->f_next = ffreelist; ffreelist = fp1; free2: (void) soclose (so2); free1: (void) soclose (so1); } sendto () { struct a { int s; caddr_t buf; int len; int flags; caddr_t to; int tolen; } * uap = (struct a *) u.u_ap; struct msghdr msg; msg.msg_name = uap->to; msg.msg_namelen = uap->tolen; msg.msg_accrights = (caddr_t) 0; msg.msg_accrightslen = 0; u.u_base = uap->buf; u.u_count = uap->len; u.u_segflg = 0; sendit (uap->s, &msg, uap->flags); } send () { struct a { int s; caddr_t buf; int len; int flags; } * uap = (struct a *) u.u_ap; struct msghdr msg; msg.msg_name = (caddr_t) 0; msg.msg_namelen = 0; msg.msg_accrights = (caddr_t) 0; msg.msg_accrightslen = 0; u.u_base = uap->buf; u.u_count = uap->len; u.u_segflg = 0; sendit (uap->s, &msg, uap->flags); } void sendit (s, mp, flags) int s; struct msghdr * mp; int flags; { struct file * fp; struct mbuf * to, * rights; if ((fp = getsock (s)) == 0) return; if (u.u_count != 0 && useracc (u.u_base, u.u_count, UACC_READ) == 0) { u.u_error = EFAULT; return; } if (mp->msg_name) { if (u.u_error = sockargs (&to, mp->msg_name, mp->msg_namelen,MT_SONAME)) return; } else to = (struct mbuf *) 0; if (mp->msg_accrights) { if (u.u_error = sockargs (&to, mp->msg_accrights, mp->msg_accrightslen, MT_SONAME)) goto bad; } else rights = (struct mbuf *) 0; u.u_error = sosend (filesock (fp), to, flags, rights); if (rights) m_freem (rights); bad: if (to) m_freem (to); } recvfrom () { struct a { int s; caddr_t buf; int len; int flags; caddr_t from; int * fromlenaddr; } * uap = (struct a *) u.u_ap; struct msghdr msg; msg.msg_name = uap->from; if (u.u_error = copyin ((caddr_t) uap->fromlenaddr, (caddr_t) &msg.msg_namelen, sizeof (msg.msg_namelen))) return; msg.msg_accrights = (caddr_t) 0; msg.msg_accrightslen = 0; u.u_base = uap->buf; u.u_count = uap->len; u.u_segflg = 0; recvit (uap->s, &msg, uap->flags, (caddr_t) uap->fromlenaddr, (caddr_t) 0); } recv () { struct a { int s; caddr_t buf; int len; int flags; } * uap = (struct a *) u.u_ap; struct msghdr msg; msg.msg_name = (caddr_t) 0; msg.msg_namelen = 0; msg.msg_accrights = (caddr_t) 0; msg.msg_accrightslen = 0; u.u_base = uap->buf; u.u_count = uap->len; u.u_segflg = 0; recvit (uap->s, &msg, uap->flags, (caddr_t) 0, (caddr_t) 0); } void recvit (s, mp, flags, namelenp, rightslenp) int s; struct msghdr * mp; int flags; caddr_t namelenp, rightslenp; { struct file * fp; struct mbuf * from, * rights; int len; if ((fp = getsock (s)) == 0) return; if (u.u_count != 0 && useracc (u.u_base, u.u_count, UACC_WRITE) == 0) { u.u_error = EFAULT; return; } u.u_error = soreceive (filesock (fp), &from, flags, &rights); if (mp->msg_name) { len = mp->msg_namelen; if (len <= 0 || from == (struct mbuf *) 0) len = 0; else { if (len > from->m_len) len = from->m_len; (void) copyout ((caddr_t) mtod (from, caddr_t), (caddr_t) mp->msg_name, (unsigned) len); } (void) copyout ((caddr_t) &len, namelenp, sizeof (int)); } if (mp->msg_accrights) { len = mp->msg_accrightslen; if (len <= 0 || rights == (struct mbuf *) 0) len = 0; else { if (len > rights->m_len) len = rights->m_len; (void) copyout ((caddr_t) mtod (rights, caddr_t), (caddr_t) mp->msg_accrights, (unsigned) len); } (void) copyout ((caddr_t) &len, rightslenp, sizeof (int)); } if (rights) m_freem (rights); if (from) m_freem (from); } setsockopt () { struct a { int s; int level; int name; caddr_t val; int valsize; } * uap = (struct a *) u.u_ap; struct file * fp; struct mbuf * m = (struct mbuf *) 0; if ((fp = getsock (uap->s)) == 0) return; if (uap->valsize > MLEN) { u.u_error = EINVAL; return; } if (uap->val) { m = m_get (M_WAIT, MT_SOOPTS); if (m == (struct mbuf *) 0) { u.u_error = ENOBUFS; return; } if (u.u_error = copyin (uap->val, mtod (m, caddr_t), (u_int) uap->valsize)) { (void) m_freem (m); return; } m->m_len = uap->valsize; } u.u_error = sosetopt (filesock (fp), uap->level, uap->name, m); } getsockopt () { struct a { int s; int level; int name; caddr_t val; int * avalsize; } * uap = (struct a *) u.u_ap; struct file * fp; struct mbuf * m = (struct mbuf *) 0; int valsize; if ((fp = getsock (uap->s)) == 0) return; if (uap->val) { if (u.u_error = copyin ((caddr_t) uap->avalsize, (caddr_t) &valsize, sizeof (valsize))) return; } else valsize = 0; if (u.u_error = sogetopt (filesock (fp), uap->level, uap->name, &m)) goto bad; if (uap->val && valsize && m != (struct mbuf *) 0) { if (valsize > m->m_len) valsize = m->m_len; if (u.u_error = copyout (mtod (m, caddr_t), uap->val, (u_int) valsize)) goto bad; u.u_error = copyout ((caddr_t) &valsize, (caddr_t) uap->avalsize, sizeof (valsize)); } bad: if (m != (struct mbuf *) 0) (void) m_freem (m); } sockpipe () { register struct file * fpr, * fpw; struct socket * sor, * sow; int r; /* * Create some sockets (2). */ if (u.u_error = socreate (AF_UNIX, &sor, SOCK_STREAM, 0)) return; if (u.u_error = socreate (AF_UNIX, &sow, SOCK_STREAM, 0)) goto free1; /* * assign them to file structures in the open file table. */ if ((fpr = falloc ((struct inode *) 0, FREAD | FWRITE)) == NULL) goto free2; fpr->f_offset = sockoffset (sor); r = u.u_rval1; if ((fpw = falloc ((struct inode *) 0, FREAD | FWRITE)) == NULL) goto free3; fpw->f_offset = sockoffset (sow); u.u_rval2 = u.u_rval1; u.u_rval1 = r; /* * Connect them together. */ if (u.u_error = unp_connect2 (sow, sor)) goto free4; /* * Close one direction. */ sor->so_state |= SS_CANTSENDMORE; sow->so_state |= SS_CANTRCVMORE; return; free4: fpw->f_count = 0; fpw->f_next = ffreelist; ffreelist = fpw; free3: fpr->f_count = 0; fpr->f_next = ffreelist; ffreelist = fpr; free2: (void) soclose (sow); free1: (void) soclose (sor); } void getsockname () { struct a { int fdes; caddr_t asa; int * alen; } * uap = (struct a *) u.u_ap; struct file * fp; struct socket * so; struct mbuf * m; int len; if ((fp = getsock (uap->fdes)) == 0) return; if (u.u_error = copyin ((caddr_t) uap->alen, (caddr_t) &len, sizeof (len))) return; so = filesock (fp); if ((m = m_getclr (M_WAIT, MT_SONAME)) == (struct mbuf *) 0) { u.u_error = ENOBUFS; return; } if (u.u_error = (* so->so_proto->pr_usrreq) (so, PRU_SOCKADDR, (struct mbuf *) 0, m, (struct mbuf *) 0)) goto bad; if (len > m->m_len) len = m->m_len; if (u.u_error = copyout (mtod (m, caddr_t), (caddr_t) uap->asa, (u_int) len)) goto bad; u.u_error = copyout ((caddr_t) &len, (caddr_t) uap->alen, sizeof (len)); bad: m_freem (m); } /* * System call helper functions */ int sockargs (aname, name, namelen, type) struct mbuf ** aname; caddr_t name; int namelen, type; { struct mbuf * m; int error; if (namelen > MLEN) return EINVAL; if ((m = m_get (M_WAIT, type)) == NULL) return ENOBUFS; m->m_len = namelen; if (error = copyin (name, mtod (m, caddr_t), (u_int) namelen)) (void) m_free (m); else * aname = m; return error; } /* given a file descriptor see if it is a socket file descriptor */ struct file * getsock (fd) int fd; { struct file * fp; /* given an fd, see if it is a valid fd, ie in file table*/ if ((fp = getf (fd)) == NULL) return 0; if (fp->f_inode) { u.u_error = ENOTSOCK; return 0; } return fp; } @//E*O*F uipc/src/syscalls.c// chmod u=rw,g=r,o=r uipc/src/syscalls.c echo x - uipc/src/sysent.m4 sed 's/^@//' > "uipc/src/sysent.m4" <<'@//E*O*F uipc/src/sysent.m4//' divert(-1) # # @(#)sysent.m4 1.1 (Alex Crain) 6/20/89 # # sysent.m4 - generate a sysent.h file from sysconfig.m4 # define(DEFSYSCALL,`define(`SYSENT_OFFSET',incr(SYSENT_OFFSET)){$1,$2},') define(DEFINE,`#define $1 $2') define(REALTIME,1) divert /* * sysent.h - system call entry definitions. * * DO NOT EDIT THIS FILE! It is generated by sysent.m4. */ /* * The new sysent structure. This looks just like the original sysent * structure, see <sys/systm.h>. The order is critical, and the array * offsets must be equal to SYSL_<call name> - SYSL_FIRST. * * The original sysent structure is not used because it defines sy_call * as an int function instead of void. */ struct void_sysent { char sy_narg; int (*sy_call)(); } sysentries[] = { include(../sysconfig.m4) }; DEFINE(SYSL_LOCSYS,SYSL_SYSCALL) DEFINE(SYSL_FIRST,SYSENT_START) DEFINE(SYSL_LAST,SYSENT_OFFSET) @//E*O*F uipc/src/sysent.m4// chmod u=rw,g=r,o=r uipc/src/sysent.m4 echo x - uipc/src/usrreq.c sed 's/^@//' > "uipc/src/usrreq.c" <<'@//E*O*F uipc/src/usrreq.c//' #ifndef LINT static char * sccsdef = "%W% %D%"; #endif /* * usrreq.c - Unix domain functions. * * Written by Alex Crain. * * This file is based in the Berkeley file uipc_socket.c, * but is *not* guarenteed to be in any way compatable. It is * close enough to the Berkeley code that the following applies... * * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. This software * is provided "as is" without express or implied warranty. * */ #include <sys/types.h> #include <uipc/conf.h> #include <sys/param.h> #include <sys/systm.h> #include <sys/user.h> #include <sys/inode.h> #include <sys/proc.h> #include <sys/stat.h> #include <sys/var.h> #include <sys/tune.h> #include <sys/errno.h> #include <uipc/mbuf.h> #include <uipc/socket.h> #include <uipc/socketvar.h> #include <uipc/protosw.h> #include <uipc/domain.h> #include <uipc/unpcb.h> #include <uipc/un.h> #include <uipc/fproto.h> struct sockaddr sun_noname = { AF_UNIX }; ino_t unp_ino; int uipc_usrreq (so, req, m, nam, rights) struct socket * so; int req; struct mbuf * m, * nam, * rights; { struct unpcb * unp = sotounpcb (so); struct socket * so2; int error = 0; if (req == PRU_CONTROL) return EOPNOTSUPP; if (req != PRU_SEND && rights && rights->m_len) { error = EOPNOTSUPP; goto release; } if (unp == (struct unpcb *) 0 && req != PRU_ATTACH) { error = EINVAL; goto release; } switch (req) { case PRU_ATTACH: if (unp) { error = EISCONN; break; } error = unp_attach (so); break; case PRU_DETACH: unp_detach (unp); break; case PRU_BIND: error = unp_bind (unp, nam); break; case PRU_LISTEN: if (unp->unp_inode == 0) error = EINVAL; break; case PRU_CONNECT: error = unp_connect (so, nam); break; case PRU_CONNECT2: error = unp_connect2 (so, (struct socket *) nam); break; case PRU_DISCONNECT: unp_disconnect (unp); break; case PRU_ACCEPT: if (unp->unp_conn && unp->unp_conn->unp_addr) { nam->m_len = unp->unp_conn->unp_addr->m_len; bcopy (mtod (unp->unp_conn->unp_addr, caddr_t), mtod (nam, caddr_t), (unsigned) nam->m_len); } else { nam->m_len = sizeof (sun_noname); * (mtod (nam, struct sockaddr *)) = sun_noname; } break; case PRU_SHUTDOWN: socantsendmore (so); unp_usrclosed (unp); break; case PRU_RCVD: switch (so->so_type) { case SOCK_DGRAM: panic ("uipc 1"); /* NOTREACHED */; case SOCK_STREAM: #define rcv (&so->so_rcv) #define snd (&so2->so_snd) if (unp->unp_conn == 0) break; /* * Adjust backpressure on sender * and wakeup any waiting to write. */ so2 = unp->unp_conn->unp_socket; snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; unp->unp_mbcnt = rcv->sb_mbcnt; snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; unp->unp_cc = rcv->sb_cc; sowwakeup (so2); #undef snd #undef rcv break; default: panic ("uipc 2"); } break; case PRU_SEND: if (rights && (error = unp_internalize (rights))) break; switch (so->so_type) { case SOCK_DGRAM: { struct sockaddr * from; if (nam) { if (unp->unp_conn) { error = EISCONN; break; } if (error = unp_connect (so, nam)) break; } else { if (unp->unp_conn == 0) { error = ENOTCONN; break; } } so2 = unp->unp_conn->unp_socket; if (unp->unp_addr) from = mtod (unp->unp_addr, struct sockaddr *); else from = &sun_noname; if (sbspace (&so2->so_rcv) > 0 && sbappendaddr (&so2->so_rcv, from, m, rights)) { sorwakeup (so2); m = 0; } else error = ENOBUFS; if (nam) unp_disconnect (unp); break; } case SOCK_STREAM: #define rcv (&so2->so_rcv) #define snd (&so->so_snd) if (so->so_state & SS_CANTSENDMORE) { error = EPIPE; break; } if (unp->unp_conn == 0) panic ("uipc 3"); so2 = unp->unp_conn->unp_socket; /* * Send to paired receive port, and then reduce * senders hiwater makrs to maintain backpressure. * Wake up readers. */ if (rights) (void) sbappendrights (rcv, m, rights); else sbappend (rcv, m); snd->sb_mbmax -= rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; unp->unp_conn->unp_cc = rcv->sb_cc; sorwakeup (so2); m = 0; break; #undef snd #undef rcv default: panic ("uipc 4"); } break; case PRU_SENSE: /* ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; */ if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { so2 = unp->unp_conn->unp_socket; /* ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; */ } ((struct stat *) m)->st_dev = NODEV; if (unp->unp_ino == 0) unp->unp_ino = unp_ino++; ((struct stat *) m)->st_ino = unp->unp_ino; return 0; case PRU_ABORT: unp_drop(unp, ECONNABORTED); break; case PRU_RCVOOB: return EOPNOTSUPP; case PRU_SENDOOB: error = EOPNOTSUPP; break; case PRU_SOCKADDR: break; case PRU_PEERADDR: if (unp->unp_conn && unp->unp_conn->unp_addr) { nam->m_len = unp->unp_conn->unp_addr->m_len; bcopy (mtod (unp->unp_conn->unp_addr, caddr_t), mtod (nam, caddr_t), (unsigned) nam->m_len); } break; case PRU_SLOWTIMO: break; default: panic ("prusrreq"); } release: if (m) m_freem (m); return error; } #define UNPST_SENDSPACE 4096 #define UNPST_RECVSPACE 4096 #define UNPDG_SENDSPACE 2048 /* max datagram size */ #define UNPDG_RECVSPACE 2048 int unp_rights; int unp_attach (so) struct socket * so; { struct mbuf * m; struct unpcb * unp; int error = 0; switch (so->so_type) { case SOCK_DGRAM: error = soreserve (so, UNPDG_SENDSPACE, UNPDG_RECVSPACE); break; case SOCK_STREAM: error = soreserve (so, UNPST_SENDSPACE, UNPST_RECVSPACE); break; } if (error) return error; if ((m = m_getclr (M_DONTWAIT, MT_PCB)) == NULL) return ENOBUFS; unp = mtod(m, struct unpcb *); so->so_pcb = (caddr_t) unp; unp->unp_socket = so; return 0; } void unp_detach (unp) struct unpcb * unp; { if (unp->unp_inode) { unp->unp_inode->i_socket = 0; iput (unp->unp_inode); unp->unp_inode = 0; } if (unp->unp_conn) unp_disconnect (unp); while (unp->unp_refs) unp_drop (unp->unp_refs, ECONNRESET); soisdisconnected (unp->unp_socket); unp->unp_socket->so_pcb = 0; m_freem (unp->unp_addr); (void) m_free (dtom (unp)); if (unp_rights) unp_gc (); } int unp_bind (unp, nam) struct unpcb * unp; struct mbuf * nam; { struct sockaddr_un * soun = mtod (nam, struct sockaddr_un *); struct inode * ip; int error; if (unp->unp_inode != NULL || nam->m_len == MLEN) return EINVAL; *(mtod (nam, caddr_t) + nam->m_len) = '\0'; u.u_dirp = soun->sun_path; if (ip = namei (schar, 1)) { iput (ip); return EADDRINUSE; } if (error = u.u_error) { u.u_error = 0; return error; } if ((ip = maknode (IFREG | 0777)) == NULL) { error = u.u_error; u.u_error = 0; return error; } ip->i_uid = u.u_uid; ip->i_gid = u.u_gid; ip->i_socket = unp->unp_socket; unp->unp_inode = ip; unp->unp_addr = m_copy (nam, 0, (int) M_COPYALL); prele (ip); return 0; } int unp_connect (so, nam) struct socket * so; struct mbuf * nam; { struct sockaddr_un * soun = mtod (nam, struct sockaddr_un *); struct inode * ip; int error; struct socket * so2; caddr_t dirp = u.u_dirp; caddr_t base = u.u_base; unsigned count = u.u_count; if ((nam->m_len + (nam->m_off - MMINOFF)) == MLEN) { error = EMSGSIZE; goto bad0; } * (mtod (nam, caddr_t) + nam->m_len) = '\0'; u.u_dirp = soun->sun_path; if ((ip = namei (schar, 0)) == 0) { error = u.u_error; u.u_error = 0; goto bad0; } if (access (ip, IWRITE)) { error = u.u_error; u.u_error = 0; goto bad; } /* does the other guy allow people to connect? */ if ((so2 = ip->i_socket) == 0) { error = ECONNREFUSED; goto bad; } /* are we the same protocol? */ if (so2->so_type != so->so_type) { error = EPROTOTYPE; goto bad; } /* looks like we setup a new socket for the accept side */ if (so->so_proto->pr_flags & PR_CONNREQUIRED && ((so2->so_options & SO_ACCEPTCONN) == 0 || (so2 = sonewconn (so2)) == 0)) { error = ECHILD; /* ECONNREFUSED;*/ goto bad; } error = unp_connect2 (so, so2); bad: iput (ip); bad0: u.u_base = base; u.u_count = count; u.u_dirp = dirp; return error; } int unp_connect2 (so1, so2) struct socket * so1, * so2; { struct unpcb * unp1, * unp2; if (so2->so_type != so1->so_type) return EPROTOTYPE; unp1 = sotounpcb (so1); unp2 = sotounpcb (so2); unp1->unp_conn = unp2; switch (so1->so_type) { case SOCK_DGRAM: unp1->unp_nextref = unp2->unp_refs; unp2->unp_refs = unp1; soisconnected (so1); break; case SOCK_STREAM: unp2->unp_conn = unp1; soisconnected (so1); soisconnected (so2); break; default: panic ("unp_connect 2"); } return 0; } void unp_disconnect (unp) struct unpcb * unp; { struct unpcb * unp2 = unp->unp_conn; if (unp2 == 0) return; unp->unp_conn = 0; switch (unp->unp_socket->so_type) { case SOCK_DGRAM: if (unp2->unp_refs == unp) unp2->unp_refs = unp->unp_nextref; else { unp2 = unp2->unp_refs; for (;;) { if (unp2 == 0) panic ("unp_disconnect"); if (unp2->unp_nextref == unp) break; unp2 = unp2->unp_nextref; } unp2->unp_nextref = unp->unp_nextref; } unp->unp_nextref = 0; unp->unp_socket->so_state &= ~SS_ISCONNECTED; break; case SOCK_STREAM: soisdisconnected (unp->unp_socket); unp2->unp_conn = 0; soisdisconnected (unp2->unp_socket); break; } } /* ARGSUSED */ void unp_usrclosed (unp) struct unpcb * unp; { /* do not very much */ ; } void unp_drop (unp, errno) struct unpcb * unp; int errno; { struct socket * so = unp->unp_socket; so->so_error = errno; unp_disconnect (unp); if (so->so_head) { so->so_pcb = (caddr_t) 0; m_freem (unp->unp_addr); (void) m_free (dtom (unp)); sofree (so); } } ushort f_msgcount[NFILEMAX]; #define fptoi(FP) (((FP)-file)/sizeof (struct file)) /* ARGSUSED */ int unp_externalize (rights) struct mbuf * rights; { int newfds = rights->m_len / sizeof (int); int i, f; struct file ** rp = mtod (rights, struct file **); struct file * fp; if (newfds > ufavail ()) { for (i = 0; i < newfds; i++) { fp = *rp; unp_discard (fp); * rp++ = 0; } return EMSGSIZE; } for (i = 0, f = 0; i < newfds; i++) { f = ufalloc (f); if (f < 0) panic ("unp_externalize"); fp = * rp; u.u_ofile[f] = fp; f_msgcount[fptoi (fp)]--; unp_rights --; * (int *) rp++ = f; } return 0; } /* ARGSUSED */ int unp_internalize (rights) struct mbuf * rights; { struct file ** rp, * fp; int oldfds = rights->m_len / sizeof (int); int i; rp = mtod (rights, struct file **); for (i = 0; i < oldfds; i++) if (getf (* (int *) rp++) == 0) return EBADF; rp = mtod (rights, struct file **); for (i = 0; i < oldfds; i++) { fp = getf (* (int *) rp); * rp++ = fp; fp->f_count++; f_msgcount[fptoi (fp)]++; unp_rights++; } return 0; } int unp_defer, unp_gcing; extern struct domain unixdomain; void unp_gc () { struct file * fp; struct socket * so; int i; if (unp_gcing) return; unp_gcing = 1; restart: unp_defer = 0; for (fp = file; fp < (struct file *) v.ve_file; fp++) fp->f_flag &= ~(FMARK | FDEFER); do { for (fp = file; fp < (struct file *) v.ve_file; fp++) { if (fp->f_count == 0) continue; if (fp->f_flag & FDEFER) { fp->f_flag &= ~FDEFER; unp_defer--; } else { if (fp->f_flag & FMARK) continue; if (fp->f_count == f_msgcount[fptoi (fp)]) continue; fp->f_flag |= FMARK; } if (fp->f_inode) continue; so = filesock (fp); if (so->so_proto->pr_domain != &unixdomain || so->so_proto->pr_flags & PR_RIGHTS) continue; if (so->so_rcv.sb_flags & SB_LOCK) { sbwait (&so->so_rcv); goto restart; } unp_scan (so->so_rcv.sb_mb, (int (*)()) unp_mark); } } while (unp_defer); for (fp = file, i = 0; fp < (struct file *) v.ve_file; fp++, i++) { if (fp->f_count == 0) continue; if (fp->f_count == f_msgcount[i] && (fp->f_flag & FMARK) == 0) while (f_msgcount[i]) unp_discard (fp); } unp_gcing = 0; } void unp_dispose (m) struct mbuf * m; { void unp_discard (); if (m) unp_scan (m, (int (*)()) unp_discard); } /* ARGSUSED */ void unp_scan (m0, op) struct mbuf * m0; int (* op)(); { struct mbuf * m; struct file ** rp; int i; int qfds; while (m0) { for (m = m0; m; m = m->m_next) if (m->m_type == MT_RIGHTS && m->m_len) { qfds = m->m_len / sizeof (struct file **); rp = mtod (m, struct file **); for (i = 0; i < qfds; i++) (* op) (* rp++); break; } m0 = m0->m_act; } } void unp_mark (fp) struct file * fp; { if (fp->f_flag & FMARK) return; unp_defer++; fp->f_flag |= (FMARK | FDEFER); } void unp_discard (fp) struct file * fp; { f_msgcount[fptoi (fp)]--; unp_rights--; closef (fp); } @//E*O*F uipc/src/usrreq.c// chmod u=rw,g=r,o=r uipc/src/usrreq.c exit 0 -- David H. Brierley Home: dave@galaxia.newport.ri.us; Work: dhb@quahog.ssd.ray.com Send comp.sources.3b1 submissions to comp-sources-3b1@galaxia.newport.ri.us %% Can I be excused, my brain is full. **