📄 sockio.c
字号:
}
return (sosetopt((struct socket *)fp->f_data, level, optname, m));
}
// -------------------------------------------------------------------------
static int bsd_sendmsg ( cyg_file *fp, const struct msghdr *m, int flags, ssize_t *retsize )
{
return bsd_sendit( fp, m, flags, retsize);
}
// -------------------------------------------------------------------------
static int bsd_recvmsg ( cyg_file *fp, struct msghdr *m, socklen_t *namelen, ssize_t *retsize )
{
return bsd_recvit( fp, m, namelen, retsize);
}
//==========================================================================
// File system call functions
// -------------------------------------------------------------------------
static int bsd_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
return (soreceive((struct socket *)fp->f_data, (struct mbuf **)0,
uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0));
}
// -------------------------------------------------------------------------
static int bsd_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
return (sosend((struct socket *)fp->f_data, (struct mbuf *)0,
uio, (struct mbuf *)0, (struct mbuf *)0, 0));
}
// -------------------------------------------------------------------------
static int bsd_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
{
return ESPIPE;
}
// -------------------------------------------------------------------------
static int bsd_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD cmd,
CYG_ADDRWORD data)
{
register struct socket *so = (struct socket *)fp->f_data;
void *p = 0;
switch (cmd) {
case FIONBIO:
if (*(int *)data)
so->so_state |= SS_NBIO;
else
so->so_state &= ~SS_NBIO;
return (0);
case FIOASYNC:
if (*(int *)data) {
so->so_state |= SS_ASYNC;
so->so_rcv.sb_flags |= SB_ASYNC;
so->so_snd.sb_flags |= SB_ASYNC;
} else {
so->so_state &= ~SS_ASYNC;
so->so_rcv.sb_flags &= ~SB_ASYNC;
so->so_snd.sb_flags &= ~SB_ASYNC;
}
return (0);
case FIONREAD:
*(int *)data = so->so_rcv.sb_cc;
return (0);
case SIOCATMARK:
*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
return (0);
}
/*
* Interface/routing/protocol specific ioctls:
* interface and routing ioctls should have a
* different entry since a socket's unnecessary
*/
if (IOCGROUP(cmd) == 'i')
return (ifioctl(so, (u_long)cmd, (caddr_t)data, p));
if (IOCGROUP(cmd) == 'r')
return (rtioctl((u_long)cmd, (caddr_t)data, p));
return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL,
(struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0));
}
// -------------------------------------------------------------------------
static int bsd_select (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info)
{
register struct socket *so = (struct socket *)fp->f_data;
register int s = splsoftnet();
switch (which) {
case FREAD:
if (soreadable(so)) {
splx(s);
return (1);
}
cyg_selrecord(info, &so->so_rcv.sb_sel);
so->so_rcv.sb_flags |= SB_SEL;
break;
case FWRITE:
if (sowriteable(so)) {
splx(s);
return (1);
}
cyg_selrecord(info, &so->so_snd.sb_sel);
so->so_snd.sb_flags |= SB_SEL;
break;
case 0:
if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) {
splx(s);
return (1);
}
cyg_selrecord(info, &so->so_rcv.sb_sel);
so->so_rcv.sb_flags |= SB_SEL;
break;
}
splx(s);
return ENOERR;
}
// -------------------------------------------------------------------------
static int bsd_fsync (struct CYG_FILE_TAG *fp, int mode )
{
// FIXME: call some sort of flush IOCTL?
return 0;
}
// -------------------------------------------------------------------------
static int bsd_close (struct CYG_FILE_TAG *fp)
{
int error = 0;
if (fp->f_data)
error = soclose((struct socket *)fp->f_data);
fp->f_data = 0;
return (error);
}
// -------------------------------------------------------------------------
static int bsd_fstat (struct CYG_FILE_TAG *fp, struct stat *buf )
{
register struct socket *so = (struct socket *)fp->f_data;
bzero((caddr_t)buf, sizeof (*buf));
// Mark socket as a fifo for now. We need to add socket types to
// sys/stat.h.
buf->st_mode = __stat_mode_FIFO;
return ((*so->so_proto->pr_usrreq)(so, PRU_SENSE,
(struct mbuf *)buf,
(struct mbuf *)0,
(struct mbuf *)0));
}
// -------------------------------------------------------------------------
static int bsd_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
{
return ENOSYS;
}
// -------------------------------------------------------------------------
static int bsd_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
{
return ENOSYS;
}
//==========================================================================
// Select support
// -------------------------------------------------------------------------
// This function is called by the lower layers to record the
// fact that a particular 'select' event is being requested.
//
void
selrecord(void *selector, struct selinfo *info)
{
// Unused by this implementation
}
// -------------------------------------------------------------------------
// This function is called to indicate that a 'select' event
// may have occurred.
//
void
selwakeup(struct selinfo *info)
{
cyg_selwakeup( info );
}
//==========================================================================
// Misc support functions
int
sockargs(mp, buf, buflen, type)
struct mbuf **mp;
caddr_t buf;
socklen_t buflen;
int type;
{
register struct sockaddr *sa;
register struct mbuf *m;
int error;
if (buflen > MLEN) {
#ifdef COMPAT_OLDSOCK
if (type == MT_SONAME && buflen <= 112)
buflen = MLEN; /* unix domain compat. hack */
else
#endif
return (EINVAL);
}
m = m_get(M_WAIT, type);
if (m == NULL)
return (ENOBUFS);
m->m_len = buflen;
error = copyin(buf, mtod(m, caddr_t), buflen);
if (error) {
(void) m_free(m);
return (error);
}
*mp = m;
if (type == MT_SONAME) {
sa = mtod(m, struct sockaddr *);
#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
sa->sa_family = sa->sa_len;
#endif
sa->sa_len = buflen;
}
return (0);
}
// -------------------------------------------------------------------------
// bsd_recvit()
// Support for message reception. This is a lightly edited version of the
// recvit() function is uipc_syscalls.c.
static int
bsd_recvit(cyg_file *fp, struct msghdr *mp, socklen_t *namelenp, ssize_t *retsize)
{
struct uio auio;
register struct iovec *iov;
register int i;
size_t len;
int error;
struct mbuf *from = 0, *control = 0;
auio.uio_iov = mp->msg_iov;
auio.uio_iovcnt = mp->msg_iovlen;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_rw = UIO_READ;
auio.uio_offset = 0; /* XXX */
auio.uio_resid = 0;
iov = mp->msg_iov;
for (i = 0; i < mp->msg_iovlen; i++, iov++) {
/* Don't allow sum > SSIZE_MAX */
if (iov->iov_len > SSIZE_MAX ||
(auio.uio_resid += iov->iov_len) > SSIZE_MAX)
return (EINVAL);
}
len = auio.uio_resid;
error = soreceive((struct socket *)fp->f_data, &from, &auio,
NULL, mp->msg_control ? &control : NULL,
&mp->msg_flags);
if (error) {
if (auio.uio_resid != len &&
(error == EINTR || error == EWOULDBLOCK))
error = 0;
}
if (error)
goto out;
*retsize = len - auio.uio_resid;
if (mp->msg_name) {
len = mp->msg_namelen;
if (len <= 0 || from == 0)
len = 0;
else {
/* save sa_len before it is destroyed by MSG_COMPAT */
if (len > from->m_len)
len = from->m_len;
/* else if len < from->m_len ??? */
#ifdef COMPAT_OLDSOCK
if (mp->msg_flags & MSG_COMPAT)
mtod(from, struct osockaddr *)->sa_family =
mtod(from, struct sockaddr *)->sa_family;
#endif
error = copyout(mtod(from, caddr_t),
(caddr_t)mp->msg_name, (unsigned)len);
if (error)
goto out;
}
mp->msg_namelen = len;
if (namelenp ) {
*namelenp = len;
#ifdef COMPAT_OLDSOCK
if (mp->msg_flags & MSG_COMPAT)
error = 0; /* old recvfrom didn't check */
else
#endif
goto out;
}
}
if (mp->msg_control) {
#ifdef COMPAT_OLDSOCK
/*
* We assume that old recvmsg calls won't receive access
* rights and other control info, esp. as control info
* is always optional and those options didn't exist in 4.3.
* If we receive rights, trim the cmsghdr; anything else
* is tossed.
*/
if (control && mp->msg_flags & MSG_COMPAT) {
if (mtod(control, struct cmsghdr *)->cmsg_level !=
SOL_SOCKET ||
mtod(control, struct cmsghdr *)->cmsg_type !=
SCM_RIGHTS) {
mp->msg_controllen = 0;
goto out;
}
control->m_len -= sizeof (struct cmsghdr);
control->m_data += sizeof (struct cmsghdr);
}
#endif
len = mp->msg_controllen;
if (len <= 0 || control == 0)
len = 0;
else {
struct mbuf *m = control;
caddr_t p = (caddr_t)mp->msg_control;
do {
i = m->m_len;
if (len < i) {
mp->msg_flags |= MSG_CTRUNC;
i = len;
}
error = copyout(mtod(m, caddr_t), p,
(unsigned)i);
if (m->m_next)
i = ALIGN(i);
p += i;
len -= i;
if (error != 0 || len <= 0)
break;
} while ((m = m->m_next) != NULL);
len = p - (caddr_t)mp->msg_control;
}
mp->msg_controllen = len;
}
out:
if (from)
m_freem(from);
if (control)
m_freem(control);
return (error);
}
// -------------------------------------------------------------------------
// sendit()
// Support for message transmission. This is a lightly edited version of the
// synonymous function is uipc_syscalls.c.
static int
bsd_sendit(cyg_file *fp, const struct msghdr *mp, int flags, ssize_t *retsize)
{
struct uio auio;
register struct iovec *iov;
register int i;
struct mbuf *to, *control;
int len, error;
auio.uio_iov = mp->msg_iov;
auio.uio_iovcnt = mp->msg_iovlen;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_rw = UIO_WRITE;
auio.uio_offset = 0; /* XXX */
auio.uio_resid = 0;
iov = mp->msg_iov;
for (i = 0; i < mp->msg_iovlen; i++, iov++) {
/* Don't allow sum > SSIZE_MAX */
if (iov->iov_len > SSIZE_MAX ||
(auio.uio_resid += iov->iov_len) > SSIZE_MAX)
return (EINVAL);
}
if (mp->msg_name) {
error = sockargs(&to, mp->msg_name, mp->msg_namelen,
MT_SONAME);
if (error)
return (error);
} else
to = 0;
if (mp->msg_control) {
if (mp->msg_controllen < sizeof(struct cmsghdr)
#ifdef COMPAT_OLDSOCK
&& mp->msg_flags != MSG_COMPAT
#endif
) {
error = EINVAL;
goto bad;
}
error = sockargs(&control, mp->msg_control,
mp->msg_controllen, MT_CONTROL);
if (error)
goto bad;
#ifdef COMPAT_OLDSOCK
if (mp->msg_flags == MSG_COMPAT) {
register struct cmsghdr *cm;
M_PREPEND(control, sizeof(*cm), M_WAIT);
if (control == 0) {
error = ENOBUFS;
goto bad;
} else {
cm = mtod(control, struct cmsghdr *);
cm->cmsg_len = control->m_len;
cm->cmsg_level = SOL_SOCKET;
cm->cmsg_type = SCM_RIGHTS;
}
}
#endif
} else
control = 0;
len = auio.uio_resid;
error = sosend((struct socket *)fp->f_data, to, &auio,
NULL, control, flags);
if (error) {
if (auio.uio_resid != len &&
(error == EINTR || error == EWOULDBLOCK))
error = 0;
#ifndef __ECOS
if (error == EPIPE)
psignal(p, SIGPIPE);
#endif
}
if (error == 0)
*retsize = len - auio.uio_resid;
bad:
if (to)
m_freem(to);
return (error);
}
//==========================================================================
// End of sockio.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -