v01i010: Latest version of uipc code, Part03/05

Bradley E. Smith brad at bradley.bradley.edu
Wed Feb 20 12:29:07 AEST 1991


Submitted-by: brad at 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 at 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 at galaxia.newport.ri.us; Work: dhb at quahog.ssd.ray.com
Send comp.sources.3b1 submissions to comp-sources-3b1 at galaxia.newport.ri.us
%% Can I be excused, my brain is full. **



More information about the Comp.sources.3b1 mailing list