uipc_socket.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,522 行 · 第 1/3 页

C
1,522
字号
	error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap);	afap->af_name[sizeof(afap->af_name)-1] = '\0';	afap->af_arg[sizeof(afap->af_arg)-1] = '\0';	if (error)		goto out;	afp = accept_filt_get(afap->af_name);	if (afp == NULL) {		error = ENOENT;		goto out;	}	MALLOC(af, struct so_accf *, sizeof(*af), M_ACCF, M_WAITOK);	bzero(af, sizeof(*af));	if (afp->accf_create != NULL) {		if (afap->af_name[0] != '\0') {			int len = strlen(afap->af_name) + 1;			MALLOC(af->so_accept_filter_str, char *, len, M_ACCF, M_WAITOK);			strcpy(af->so_accept_filter_str, afap->af_name);		}		af->so_accept_filter_arg = afp->accf_create(so, afap->af_arg);		if (af->so_accept_filter_arg == NULL) {			FREE(af->so_accept_filter_str, M_ACCF);			FREE(af, M_ACCF);			so->so_accf = NULL;			error = EINVAL;			goto out;		}	}	af->so_accept_filter = afp;	so->so_accf = af;	so->so_options |= SO_ACCEPTFILTER;out:	if (afap != NULL)		FREE(afap, M_TEMP);	return (error);}#endif /* INET *//* * Perhaps this routine, and sooptcopyout(), below, ought to come in * an additional variant to handle the case where the option value needs * to be some kind of integer, but not a specific size. * In addition to their use here, these functions are also called by the * protocol-level pr_ctloutput() routines. */intsooptcopyin(sopt, buf, len, minlen)	struct	sockopt *sopt;	void	*buf;	size_t	len;	size_t	minlen;{	size_t	valsize;	/*	 * If the user gives us more than we wanted, we ignore it,	 * but if we don't get the minimum length the caller	 * wants, we return EINVAL.  On success, sopt->sopt_valsize	 * is set to however much we actually retrieved.	 */	if ((valsize = sopt->sopt_valsize) < minlen)		return EINVAL;	if (valsize > len)		sopt->sopt_valsize = valsize = len;	if (sopt->sopt_p != 0)		return (copyin(sopt->sopt_val, buf, valsize));	bcopy(sopt->sopt_val, buf, valsize);	return 0;}intsosetopt(so, sopt)	struct socket *so;	struct sockopt *sopt;{	int	error, optval;	struct	linger l;	struct	timeval tv;	u_long  val;	error = 0;	if (sopt->sopt_level != SOL_SOCKET) {		if (so->so_proto && so->so_proto->pr_ctloutput)			return ((*so->so_proto->pr_ctloutput)				  (so, sopt));		error = ENOPROTOOPT;	} else {		switch (sopt->sopt_name) {#ifdef INET		case SO_ACCEPTFILTER:			error = do_setopt_accept_filter(so, sopt);			if (error)				goto bad;			break;#endif /* INET */		case SO_LINGER:			error = sooptcopyin(sopt, &l, sizeof l, sizeof l);			if (error)				goto bad;			so->so_linger = l.l_linger;			if (l.l_onoff)				so->so_options |= SO_LINGER;			else				so->so_options &= ~SO_LINGER;			break;		case SO_DEBUG:		case SO_KEEPALIVE:		case SO_DONTROUTE:		case SO_USELOOPBACK:		case SO_BROADCAST:		case SO_REUSEADDR:		case SO_REUSEPORT:		case SO_OOBINLINE:		case SO_TIMESTAMP:			error = sooptcopyin(sopt, &optval, sizeof optval,					    sizeof optval);			if (error)				goto bad;			if (optval)				so->so_options |= sopt->sopt_name;			else				so->so_options &= ~sopt->sopt_name;			break;		case SO_SNDBUF:		case SO_RCVBUF:		case SO_SNDLOWAT:		case SO_RCVLOWAT:			error = sooptcopyin(sopt, &optval, sizeof optval,					    sizeof optval);			if (error)				goto bad;			/*			 * Values < 1 make no sense for any of these			 * options, so disallow them.			 */			if (optval < 1) {				error = EINVAL;				goto bad;			}			switch (sopt->sopt_name) {			case SO_SNDBUF:			case SO_RCVBUF:				if (sbreserve(sopt->sopt_name == SO_SNDBUF ?				    &so->so_snd : &so->so_rcv, (u_long)optval,				    so, curproc) == 0) {					error = ENOBUFS;					goto bad;				}				break;			/*			 * Make sure the low-water is never greater than			 * the high-water.			 */			case SO_SNDLOWAT:				so->so_snd.sb_lowat =				    (optval > so->so_snd.sb_hiwat) ?				    so->so_snd.sb_hiwat : optval;				break;			case SO_RCVLOWAT:				so->so_rcv.sb_lowat =				    (optval > so->so_rcv.sb_hiwat) ?				    so->so_rcv.sb_hiwat : optval;				break;			}			break;		case SO_SNDTIMEO:		case SO_RCVTIMEO:			error = sooptcopyin(sopt, &tv, sizeof tv,					    sizeof tv);			if (error)				goto bad;			/* assert(hz > 0); */			if (tv.tv_sec < 0 || tv.tv_sec > SHRT_MAX / hz ||			    tv.tv_usec < 0 || tv.tv_usec >= 1000000) {				error = EDOM;				goto bad;			}			/* assert(tick > 0); */			/* assert(ULONG_MAX - SHRT_MAX >= 1000000); */			val = (u_long)(tv.tv_sec * hz) + tv.tv_usec / tick;			if (val > SHRT_MAX) {				error = EDOM;				goto bad;			}			switch (sopt->sopt_name) {			case SO_SNDTIMEO:				so->so_snd.sb_timeo = val;				break;			case SO_RCVTIMEO:				so->so_rcv.sb_timeo = val;				break;			}			break;		default:			error = ENOPROTOOPT;			break;		}		if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) {			(void) ((*so->so_proto->pr_ctloutput)				  (so, sopt));		}	}bad:	return (error);}/* Helper routine for getsockopt */intsooptcopyout(sopt, buf, len)	struct	sockopt *sopt;	void	*buf;	size_t	len;{	int	error;	size_t	valsize;	error = 0;	/*	 * Documented get behavior is that we always return a value,	 * possibly truncated to fit in the user's buffer.	 * Traditional behavior is that we always tell the user	 * precisely how much we copied, rather than something useful	 * like the total amount we had available for her.	 * Note that this interface is not idempotent; the entire answer must	 * generated ahead of time.	 */	valsize = min(len, sopt->sopt_valsize);	sopt->sopt_valsize = valsize;	if (sopt->sopt_val != 0) {		if (sopt->sopt_p != 0)			error = copyout(buf, sopt->sopt_val, valsize);		else			bcopy(buf, sopt->sopt_val, valsize);	}	return error;}intsogetopt(so, sopt)	struct socket *so;	struct sockopt *sopt;{	int	error, optval;	struct	linger l;	struct	timeval tv;	struct accept_filter_arg *afap;	error = 0;	if (sopt->sopt_level != SOL_SOCKET) {		if (so->so_proto && so->so_proto->pr_ctloutput) {			return ((*so->so_proto->pr_ctloutput)				  (so, sopt));		} else			return (ENOPROTOOPT);	} else {		switch (sopt->sopt_name) {#ifdef INET		case SO_ACCEPTFILTER:			if ((so->so_options & SO_ACCEPTCONN) == 0)				return (EINVAL);			MALLOC(afap, struct accept_filter_arg *, sizeof(*afap),				M_TEMP, M_WAITOK);			bzero(afap, sizeof(*afap));			if ((so->so_options & SO_ACCEPTFILTER) != 0) {				strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name);				if (so->so_accf->so_accept_filter_str != NULL)					strcpy(afap->af_arg, so->so_accf->so_accept_filter_str);			}			error = sooptcopyout(sopt, afap, sizeof(*afap));			FREE(afap, M_TEMP);			break;#endif /* INET */					case SO_LINGER:			l.l_onoff = so->so_options & SO_LINGER;			l.l_linger = so->so_linger;			error = sooptcopyout(sopt, &l, sizeof l);			break;		case SO_USELOOPBACK:		case SO_DONTROUTE:		case SO_DEBUG:		case SO_KEEPALIVE:		case SO_REUSEADDR:		case SO_REUSEPORT:		case SO_BROADCAST:		case SO_OOBINLINE:		case SO_TIMESTAMP:			optval = so->so_options & sopt->sopt_name;integer:			error = sooptcopyout(sopt, &optval, sizeof optval);			break;		case SO_TYPE:			optval = so->so_type;			goto integer;		case SO_ERROR:			optval = so->so_error;			so->so_error = 0;			goto integer;		case SO_SNDBUF:			optval = so->so_snd.sb_hiwat;			goto integer;		case SO_RCVBUF:			optval = so->so_rcv.sb_hiwat;			goto integer;		case SO_SNDLOWAT:			optval = so->so_snd.sb_lowat;			goto integer;		case SO_RCVLOWAT:			optval = so->so_rcv.sb_lowat;			goto integer;		case SO_SNDTIMEO:		case SO_RCVTIMEO:			optval = (sopt->sopt_name == SO_SNDTIMEO ?				  so->so_snd.sb_timeo : so->so_rcv.sb_timeo);			tv.tv_sec = optval / hz;			tv.tv_usec = (optval % hz) * tick;			error = sooptcopyout(sopt, &tv, sizeof tv);			break;					default:			error = ENOPROTOOPT;			break;		}		return (error);	}}/* XXX; prepare mbuf for (__FreeBSD__ < 3) routines. */intsoopt_getm(struct sockopt *sopt, struct mbuf **mp){	struct mbuf *m, *m_prev;	int sopt_size = sopt->sopt_valsize;	MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_DATA);	if (m == 0) {		return ENOBUFS;        }	if (sopt_size > MLEN) {		MCLGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT);		if ((m->m_flags & M_EXT) == 0) {			m_free(m);			return ENOBUFS;		}		m->m_len = min(MCLBYTES, sopt_size);	} else {		m->m_len = min(MLEN, sopt_size);	}	sopt_size -= m->m_len;	*mp = m;	m_prev = m;	while (sopt_size) {		MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_DATA);		if (m == 0) {			m_freem(*mp);			return ENOBUFS;		}		if (sopt_size > MLEN) {			MCLGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT);			if ((m->m_flags & M_EXT) == 0) {				m_freem(*mp);				return ENOBUFS;			}			m->m_len = min(MCLBYTES, sopt_size);		} else {			m->m_len = min(MLEN, sopt_size);		}		sopt_size -= m->m_len;		m_prev->m_next = m;		m_prev = m;	}	return 0;}/* XXX; copyin sopt data into mbuf chain for (__FreeBSD__ < 3) routines. */intsoopt_mcopyin(struct sockopt *sopt, struct mbuf *m){	struct mbuf *m0 = m;	if (sopt->sopt_val == NULL)		return 0;	while (m != NULL && sopt->sopt_valsize >= m->m_len) {		if (sopt->sopt_p != NULL) {			int error;			error = copyin(sopt->sopt_val, mtod(m, char *),				       m->m_len);			if (error != 0) {				m_freem(m0);				return(error);			}		} else			bcopy(sopt->sopt_val, mtod(m, char *), m->m_len);		sopt->sopt_valsize -= m->m_len;		(caddr_t)sopt->sopt_val += m->m_len;		m = m->m_next;	}	if (m != NULL) /* should be allocated enoughly at ip6_sooptmcopyin() */		panic("ip6_sooptmcopyin");	return 0;}/* XXX; copyout mbuf chain data into soopt for (__FreeBSD__ < 3) routines. */intsoopt_mcopyout(struct sockopt *sopt, struct mbuf *m){	struct mbuf *m0 = m;	size_t valsize = 0;	if (sopt->sopt_val == NULL)		return 0;	while (m != NULL && sopt->sopt_valsize >= m->m_len) {		if (sopt->sopt_p != NULL) {			int error;			error = copyout(mtod(m, char *), sopt->sopt_val,				       m->m_len);			if (error != 0) {				m_freem(m0);				return(error);			}		} else			bcopy(mtod(m, char *), sopt->sopt_val, m->m_len);	       sopt->sopt_valsize -= m->m_len;	       (caddr_t)sopt->sopt_val += m->m_len;	       valsize += m->m_len;	       m = m->m_next;	}	if (m != NULL) {		/* enough soopt buffer should be given from user-land */		m_freem(m0);		return(EINVAL);	}	sopt->sopt_valsize = valsize;	return 0;}voidsohasoutofband(so)	register struct socket *so;{	selwakeup(&so->so_rcv.sb_sel);}intsopoll(struct socket *so, int events, struct ucred *cred, struct proc *p){    panic("%s\n", __FUNCTION__);    return 0;#if 0 // POLL	int revents = 0;	int s = splnet();	if (events & (POLLIN | POLLRDNORM))		if (soreadable(so))			revents |= events & (POLLIN | POLLRDNORM);	if (events & (POLLOUT | POLLWRNORM))		if (sowriteable(so))			revents |= events & (POLLOUT | POLLWRNORM);	if (events & (POLLPRI | POLLRDBAND))		if (so->so_oobmark || (so->so_state & SS_RCVATMARK))			revents |= events & (POLLPRI | POLLRDBAND);	if (revents == 0) {		if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {			selrecord(p, &so->so_rcv.sb_sel);			so->so_rcv.sb_flags |= SB_SEL;		}		if (events & (POLLOUT | POLLWRNORM)) {			selrecord(p, &so->so_snd.sb_sel);			so->so_snd.sb_flags |= SB_SEL;		}	}	splx(s);	return (revents);#endif // POLL}

⌨️ 快捷键说明

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