⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uipc_usrreq.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	vattr.va_type = VSOCK;	vattr.va_mode = ACCESSPERMS;	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);	if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr))		return (error);	vp = nd.ni_vp;	vp->v_socket = unp->unp_socket;	unp->unp_vnode = vp;	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);	VOP_UNLOCK(vp);	return (0);}unp_connect(so, nam, p)	struct socket *so;	struct mbuf *nam;	struct proc *p;{	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);	register struct vnode *vp;	register struct socket *so2, *so3;	struct unpcb *unp2, *unp3;	int error;	struct nameidata nd;	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);	if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) {	/* XXX */		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)			return (EMSGSIZE);	} else		*(mtod(nam, caddr_t) + nam->m_len) = 0;	if (error = namei(&nd))		return (error);	vp = nd.ni_vp;	if (vp->v_type != VSOCK) {		error = ENOTSOCK;		goto bad;	}	if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))		goto bad;	so2 = vp->v_socket;	if (so2 == 0) {		error = ECONNREFUSED;		goto bad;	}	if (so->so_type != so2->so_type) {		error = EPROTOTYPE;		goto bad;	}	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||		    (so3 = sonewconn(so2, 0)) == 0) {			error = ECONNREFUSED;			goto bad;		}		unp2 = sotounpcb(so2);		unp3 = sotounpcb(so3);		if (unp2->unp_addr)			unp3->unp_addr =				  m_copy(unp2->unp_addr, 0, (int)M_COPYALL);		so2 = so3;	}	error = unp_connect2(so, so2);bad:	vput(vp);	return (error);}unp_connect2(so, so2)	register struct socket *so;	register struct socket *so2;{	register struct unpcb *unp = sotounpcb(so);	register struct unpcb *unp2;	if (so2->so_type != so->so_type)		return (EPROTOTYPE);	unp2 = sotounpcb(so2);	unp->unp_conn = unp2;	switch (so->so_type) {	case SOCK_DGRAM:		unp->unp_nextref = unp2->unp_refs;		unp2->unp_refs = unp;		soisconnected(so);		break;	case SOCK_STREAM:		unp2->unp_conn = unp;		soisconnected(so);		soisconnected(so2);		break;	default:		panic("unp_connect2");	}	return (0);}unp_disconnect(unp)	struct unpcb *unp;{	register 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;	}}#ifdef notdefunp_abort(unp)	struct unpcb *unp;{	unp_detach(unp);}#endifunp_shutdown(unp)	struct unpcb *unp;{	struct socket *so;	if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&	    (so = unp->unp_conn->unp_socket))		socantrcvmore(so);}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);	}}#ifdef notdefunp_drain(){}#endifunp_externalize(rights)	struct mbuf *rights;{	struct proc *p = curproc;		/* XXX */	register int i;	register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);	register struct file **rp = (struct file **)(cm + 1);	register struct file *fp;	int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);	int f;	if (!fdavail(p, newfds)) {		for (i = 0; i < newfds; i++) {			fp = *rp;			unp_discard(fp);			*rp++ = 0;		}		return (EMSGSIZE);	}	for (i = 0; i < newfds; i++) {		if (fdalloc(p, 0, &f))			panic("unp_externalize");		fp = *rp;		p->p_fd->fd_ofiles[f] = fp;		fp->f_msgcount--;		unp_rights--;		*(int *)rp++ = f;	}	return (0);}unp_internalize(control, p)	struct mbuf *control;	struct proc *p;{	struct filedesc *fdp = p->p_fd;	register struct cmsghdr *cm = mtod(control, struct cmsghdr *);	register struct file **rp;	register struct file *fp;	register int i, fd;	int oldfds;	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||	    cm->cmsg_len != control->m_len)		return (EINVAL);	oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);	rp = (struct file **)(cm + 1);	for (i = 0; i < oldfds; i++) {		fd = *(int *)rp++;		if ((unsigned)fd >= fdp->fd_nfiles ||		    fdp->fd_ofiles[fd] == NULL)			return (EBADF);	}	rp = (struct file **)(cm + 1);	for (i = 0; i < oldfds; i++) {		fp = fdp->fd_ofiles[*(int *)rp];		*rp++ = fp;		fp->f_count++;		fp->f_msgcount++;		unp_rights++;	}	return (0);}int	unp_defer, unp_gcing;int	unp_mark();extern	struct domain unixdomain;unp_gc(){	register struct file *fp, *nextfp;	register struct socket *so;	struct file **extra_ref, **fpp;	int nunref, i;	if (unp_gcing)		return;	unp_gcing = 1;	unp_defer = 0;	for (fp = filehead; fp; fp = fp->f_filef)		fp->f_flag &= ~(FMARK|FDEFER);	do {		for (fp = filehead; fp; fp = fp->f_filef) {			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 == fp->f_msgcount)					continue;				fp->f_flag |= FMARK;			}			if (fp->f_type != DTYPE_SOCKET ||			    (so = (struct socket *)fp->f_data) == 0)				continue;			if (so->so_proto->pr_domain != &unixdomain ||			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)				continue;#ifdef notdef			if (so->so_rcv.sb_flags & SB_LOCK) {				/*				 * This is problematical; it's not clear				 * we need to wait for the sockbuf to be				 * unlocked (on a uniprocessor, at least),				 * and it's also not clear what to do				 * if sbwait returns an error due to receipt				 * of a signal.  If sbwait does return				 * an error, we'll go into an infinite				 * loop.  Delete all of this for now.				 */				(void) sbwait(&so->so_rcv);				goto restart;			}#endif			unp_scan(so->so_rcv.sb_mb, unp_mark);		}	} while (unp_defer);	/*	 * We grab an extra reference to each of the file table entries	 * that are not otherwise accessible and then free the rights	 * that are stored in messages on them.	 *	 * The bug in the orginal code is a little tricky, so I'll describe	 * what's wrong with it here.	 *	 * It is incorrect to simply unp_discard each entry for f_msgcount	 * times -- consider the case of sockets A and B that contain	 * references to each other.  On a last close of some other socket,	 * we trigger a gc since the number of outstanding rights (unp_rights)	 * is non-zero.  If during the sweep phase the gc code un_discards,	 * we end up doing a (full) closef on the descriptor.  A closef on A	 * results in the following chain.  Closef calls soo_close, which	 * calls soclose.   Soclose calls first (through the switch	 * uipc_usrreq) unp_detach, which re-invokes unp_gc.  Unp_gc simply	 * returns because the previous instance had set unp_gcing, and	 * we return all the way back to soclose, which marks the socket	 * with SS_NOFDREF, and then calls sofree.  Sofree calls sorflush	 * to free up the rights that are queued in messages on the socket A,	 * i.e., the reference on B.  The sorflush calls via the dom_dispose	 * switch unp_dispose, which unp_scans with unp_discard.  This second	 * instance of unp_discard just calls closef on B.	 *	 * Well, a similar chain occurs on B, resulting in a sorflush on B,	 * which results in another closef on A.  Unfortunately, A is already	 * being closed, and the descriptor has already been marked with	 * SS_NOFDREF, and soclose panics at this point.	 *	 * Here, we first take an extra reference to each inaccessible	 * descriptor.  Then, we call sorflush ourself, since we know	 * it is a Unix domain socket anyhow.  After we destroy all the	 * rights carried in messages, we do a last closef to get rid	 * of our extra reference.  This is the last close, and the	 * unp_detach etc will shut down the socket.	 *	 * 91/09/19, bsy@cs.cmu.edu	 */	extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK);	for (nunref = 0, fp = filehead, fpp = extra_ref; fp; fp = nextfp) {		nextfp = fp->f_filef;		if (fp->f_count == 0)			continue;		if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) {			*fpp++ = fp;			nunref++;			fp->f_count++;		}	}	for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)		sorflush((struct socket *)(*fpp)->f_data);	for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)		closef(*fpp);	free((caddr_t)extra_ref, M_FILE);	unp_gcing = 0;}unp_dispose(m)	struct mbuf *m;{	int unp_discard();	if (m)		unp_scan(m, unp_discard);}unp_scan(m0, op)	register struct mbuf *m0;	int (*op)();{	register struct mbuf *m;	register struct file **rp;	register struct cmsghdr *cm;	register int i;	int qfds;	while (m0) {		for (m = m0; m; m = m->m_next)			if (m->m_type == MT_CONTROL &&			    m->m_len >= sizeof(*cm)) {				cm = mtod(m, struct cmsghdr *);				if (cm->cmsg_level != SOL_SOCKET ||				    cm->cmsg_type != SCM_RIGHTS)					continue;				qfds = (cm->cmsg_len - sizeof *cm)						/ sizeof (struct file *);				rp = (struct file **)(cm + 1);				for (i = 0; i < qfds; i++)					(*op)(*rp++);				break;		/* XXX, but saves time */			}		m0 = m0->m_act;	}}unp_mark(fp)	struct file *fp;{	if (fp->f_flag & FMARK)		return;	unp_defer++;	fp->f_flag |= (FMARK|FDEFER);}unp_discard(fp)	struct file *fp;{	fp->f_msgcount--;	unp_rights--;	(void) closef(fp, (struct proc *)NULL);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -