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