4.1cBSD/a/sys/sys/sys_socket.c

Compare this file to the similar file:
Show the results in this format:

/*	sys_socket.c	4.43	83/03/04	*/

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/file.h"
#include "../h/inode.h"
#include "../h/buf.h"
#include "../h/mbuf.h"
#include "../h/protosw.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/descrip.h"
#include "../h/uio.h"

/*
 * System call interface to the socket abstraction.
 */

socket()
{
	register struct a {
		int	domain;
		int	type;
		int	protocol;
	} *uap = (struct a *)u.u_ap;
	struct socket *so;
	register struct file *fp;

	if ((fp = falloc()) == NULL)
		return;
	fp->f_flag = FREAD|FWRITE;
	fp->f_type = DTYPE_SOCKET;
	u.u_error = socreate(uap->domain, &so, uap->type, uap->protocol);
	if (u.u_error)
		goto bad;
	fp->f_socket = so;
	return;
bad:
	u.u_ofile[u.u_r.r_val1] = 0;
	fp->f_count = 0;
}

bind()
{
	register struct a {
		int	s;
		caddr_t	name;
		int	namelen;
	} *uap = (struct a *)u.u_ap;
	register struct file *fp;
	struct mbuf *nam;

	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	u.u_error = sockname(&nam, uap->name, uap->namelen);
	if (u.u_error)
		return;
	u.u_error = sobind(fp->f_socket, nam);
	m_freem(nam);
}

listen()
{
	register struct a {
		int	s;
		int	backlog;
	} *uap = (struct a *)u.u_ap;
	register struct file *fp;

	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	u.u_error = solisten(fp->f_socket, uap->backlog);
}

accept()
{
	register struct a {
		int	s;
		caddr_t	name;
		int	*anamelen;
	} *uap = (struct a *)u.u_ap;
	register struct file *fp;
	struct mbuf *nam;
	int namelen;
	int s;
	register struct socket *so;

	if (uap->name == 0)
		goto noname;
	u.u_error = copyin((caddr_t)uap->anamelen, (caddr_t)&namelen,
		sizeof (namelen));
	if (u.u_error)
		return;
	if (useracc((caddr_t)uap->name, (u_int)namelen, B_WRITE) == 0) {
		u.u_error = EFAULT;
		return;
	}
noname:
	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	s = splnet();
	so = fp->f_socket;
	if ((so->so_options & SO_ACCEPTCONN) == 0) {
		u.u_error = EINVAL;
		splx(s);
		return;
	}
	if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
		u.u_error = EWOULDBLOCK;
		splx(s);
		return;
	}
	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;
		splx(s);
		return;
	}
	if ((so->so_options & SO_NEWFDONCONN) == 0) {
		struct socket *nso = so->so_q;
		(void) soqremque(nso, 1);
		u.u_error = soclose(so, 1);
		fp->f_socket = nso;
		nso->so_q = 0;
		so = nso;
		goto ret;
	}
	if (ufalloc() < 0) {
		splx(s);
		return;
	}
	fp = falloc();
	if (fp == 0) {
		u.u_ofile[u.u_r.r_val1] = 0;
		splx(s);
		return;
	}
	{ struct socket *aso = so->so_q;
	  if (soqremque(aso, 1) == 0)
		panic("accept");
	  so = aso;
	}
	fp->f_type = DTYPE_SOCKET;
	fp->f_flag = FREAD|FWRITE;
	fp->f_socket = so;
ret:
	nam = m_get(M_WAIT, MT_SONAME);
	(void) soaccept(so, nam);
	if (uap->name) {
		if (namelen > nam->m_len)
			namelen = nam->m_len;
		/* SHOULD COPY OUT A CHAIN HERE */
		(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);
	splx(s);
}

connect()
{
	register struct a {
		int	s;
		caddr_t	name;
		int	namelen;
	} *uap = (struct a *)u.u_ap;
	register struct file *fp;
	register struct socket *so;
	struct mbuf *nam;
	int s;

	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	so = fp->f_socket;
	u.u_error = sockname(&nam, uap->name, uap->namelen);
	if (u.u_error)
		return;
	u.u_error = soconnect(so, nam);
	if (u.u_error)
		goto bad;
	s = splnet();
	if ((so->so_state & SS_NBIO) &&
	    (so->so_state & SS_ISCONNECTING)) {
		u.u_error = EINPROGRESS;
		splx(s);
		goto bad;
	}
	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;
	splx(s);
bad:
	m_freem(nam);
}

socketpair()
{

	u.u_error = ENOENT;
}

sendto()
{
	register struct a {
		int	s;
		caddr_t	buf;
		int	len;
		int	flags;
		caddr_t	to;
		int	tolen;
	} *uap = (struct a *)u.u_ap;
	register struct file *fp;
	struct uio auio;
	struct iovec aiov;
	struct mbuf *to;

	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	auio.uio_iov = &aiov;
	auio.uio_iovcnt = 1;
	aiov.iov_base = uap->buf;
	aiov.iov_len = uap->len;
	auio.uio_resid = uap->len;
	auio.uio_segflg = 0;
	auio.uio_offset = 0;	/* XXX */
	if (useracc(uap->buf, (u_int)uap->len, B_READ) == 0) {
		u.u_error = EFAULT;
		return;
	}
	u.u_error = sockname(&to, uap->to, uap->tolen);
	if (u.u_error)
		return;
	u.u_error = sosend(fp->f_socket, to, &auio, uap->flags);
	u.u_r.r_val1 = uap->len - auio.uio_resid;
	m_freem(to);
}

send()
{
	register struct a {
		int	s;
		caddr_t	buf;
		int	len;
		int	flags;
	} *uap = (struct a *)u.u_ap;
	register struct file *fp;
	struct uio auio;
	struct iovec aiov;

	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	auio.uio_iov = &aiov;
	auio.uio_iovcnt = 1;
	aiov.iov_base = uap->buf;
	aiov.iov_len = uap->len;
	auio.uio_resid = uap->len;
	auio.uio_segflg = 0;
	auio.uio_offset = 0;	/* XXX */
	if (useracc(uap->buf, (u_int)uap->len, B_READ) == 0) {
		u.u_error = EFAULT;
		return;
	}
	if (u.u_error)
		return;
	u.u_error = sosend(fp->f_socket, (struct mbuf *)0, &auio, uap->flags);
	u.u_r.r_val1 = uap->len - auio.uio_resid;
}

recvfrom()
{
	register struct a {
		int	s;
		caddr_t	buf;
		int	len;
		int	flags;
		caddr_t	from;
		int	*fromlenaddr;
	} *uap = (struct a *)u.u_ap;
	register struct file *fp;
	struct uio auio;
	struct iovec aiov;
	struct mbuf *from;
	int fromlen;

	u.u_error = copyin((caddr_t)uap->fromlenaddr, (caddr_t)&fromlen,
		sizeof (fromlen));
	if (u.u_error)
		return;
	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	auio.uio_iov = &aiov;
	auio.uio_iovcnt = 1;
	aiov.iov_base = uap->buf;
	aiov.iov_len = uap->len;
	auio.uio_resid = uap->len;
	auio.uio_segflg = 0;
	auio.uio_offset = 0;	/* XXX */
	if (useracc(uap->buf, (u_int)uap->len, B_WRITE) == 0)  {
		u.u_error = EFAULT;
		return;
	}
	from = 0;
	u.u_error = soreceive(fp->f_socket, &from, &auio, uap->flags);
	if (u.u_error)
		goto bad;
	if (from == 0)
		fromlen = 0;
	else {
		if (fromlen > from->m_len)
			fromlen = from->m_len;
		u.u_error = copyout(mtod(from, caddr_t), uap->from,
			(u_int)fromlen);
		if (u.u_error)
			goto bad;
	}
	u.u_error = copyout((caddr_t)&fromlen, (caddr_t)uap->fromlenaddr,
	    sizeof (fromlen));
	if (u.u_error)
		goto bad;
	u.u_r.r_val1 = uap->len - auio.uio_resid;
bad:
	if (from)
		m_freem(from);
}

recv()
{
	register struct a {
		int	s;
		caddr_t	buf;
		int	len;
		int	flags;
	} *uap = (struct a *)u.u_ap;
	register struct file *fp;
	struct uio auio;
	struct iovec aiov;

	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	auio.uio_iov = &aiov;
	auio.uio_iovcnt = 1;
	aiov.iov_base = uap->buf;
	aiov.iov_len = uap->len;
	auio.uio_resid = uap->len;
	auio.uio_segflg = 0;
	auio.uio_offset = 0;	/* XXX */
	if (useracc(uap->buf, (u_int)uap->len, B_WRITE) == 0)  {
		u.u_error = EFAULT;
		return;
	}
	u.u_error =
	    soreceive(fp->f_socket, (struct mbuf **)0, &auio, uap->flags);
	u.u_r.r_val1 = uap->len - auio.uio_resid;
}

sendmsg()
{

	u.u_error = EINVAL;
}

recvmsg()
{

	u.u_error = EINVAL;
}

shutdown()
{
	struct a {
		int	s;
		int	how;
	} *uap = (struct a *)u.u_ap;
	struct file *fp;

	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	u.u_error = soshutdown(fp->f_socket, uap->how);
}

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 = NULL;

	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	if (uap->valsize > MLEN) {
		u.u_error = EINVAL;
		return;
	}
	if (uap->val) {
		m = m_get(M_WAIT, MT_SOOPTS);
		if (m == 0) {
			u.u_error = ENOBUFS;
			return;
		}
		u.u_error = copyin(uap->val, mtod(m, caddr_t),
		  (u_int)uap->valsize);
		if (u.u_error)
			goto bad;
		m->m_len = uap->valsize;
	}
	u.u_error = sosetopt(fp->f_socket, uap->level, uap->name, m);
bad:
	if (m != NULL)
		(void) m_free(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 = NULL;
	int valsize;

	fp = getf(uap->s);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	if (uap->val) {
		u.u_error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize,
			sizeof (valsize));
		if (u.u_error)
			return;
		m = m_get(M_WAIT, MT_SOOPTS);
		if (m == NULL) {
			u.u_error = ENOBUFS;
			return;
		}
	}
	u.u_error = sogetopt(fp->f_socket, uap->level, uap->name, m);
	if (u.u_error)
		goto bad;
	if (uap->val) {
		if (valsize > m->m_len)
			valsize = m->m_len;
		u.u_error = copyout(mtod(m, caddr_t), uap->val, (u_int)valsize);
		if (u.u_error)
			goto bad;
		u.u_error = copyout((caddr_t)&valsize, (caddr_t)uap->avalsize,
		    sizeof (valsize));
	}
bad:
	if (m != NULL)
		(void) m_free(m);
}

pipe()
{
	register struct file *rf, *wf;
	struct socket *rso, *wso;
	int r;

	u.u_error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0,
		(struct socketopt *)0);
	if (u.u_error)
		return;
	u.u_error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0,
		(struct socketopt *)0);
	if (u.u_error)
		goto free;
	rf = falloc();
	if (rf == NULL)
		goto free2;
	r = u.u_r.r_val1;
	rf->f_flag = FREAD;
	rf->f_type = DTYPE_SOCKET;
	rf->f_socket = rso;
	wf = falloc();
	if (wf == NULL)
		goto free3;
	wf->f_flag = FWRITE;
	wf->f_type = DTYPE_SOCKET;
	wf->f_socket = wso;
	u.u_r.r_val2 = u.u_r.r_val1;
	u.u_r.r_val1 = r;
	if (piconnect(wso, rso) == 0)
		goto free4;
	return;
free4:
	wf->f_count = 0;
	u.u_ofile[u.u_r.r_val2] = 0;
free3:
	rf->f_count = 0;
	u.u_ofile[r] = 0;
free2:
	wso->so_state |= SS_NOFDREF;
	sofree(wso);
free:
	rso->so_state |= SS_NOFDREF;
	sofree(rso);
}

/*
 * Get socket address.
 */
ssocketaddr()
{
	register struct a {
		int	fdes;
		struct	sockaddr *asa;
	} *uap = (struct a *)u.u_ap;
	register struct file *fp;
	register struct socket *so;
	struct mbuf *m;

	fp = getf(uap->fdes);
	if (fp == 0)
		return;
	if (fp->f_type != DTYPE_SOCKET) {
		u.u_error = ENOTSOCK;
		return;
	}
	so = fp->f_socket;
	m = m_getclr(M_WAIT, MT_SONAME);
	u.u_error =
		(*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0);
	if (u.u_error)
		goto bad;
	u.u_error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa,
		sizeof (struct sockaddr));
bad:
	m_freem(m);
}

sockname(aname, name, namelen)
	struct mbuf **aname;
	caddr_t name;
	int namelen;
{
	register struct mbuf *m;
	int error;

	if (namelen > MLEN)
		return (EINVAL);
	m = m_get(M_WAIT, MT_SONAME);
	m->m_len = namelen;
	error = copyin(name, mtod(m, caddr_t), (u_int)namelen);
	if (error)
		(void) m_free(m);
	else
		*aname = m;
	return (error);
}