📄 sockio.c
字号:
//==========================================================================
//
// sys/kern/sockio.c
//
// Socket interface to Fileio subsystem
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD or other sources,
// and are covered by the appropriate copyright disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): nickg
// Contributors: nickg
// Date: 2000-06-06
// Purpose:
// Description:
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
/*
* Copyright (c) 1982, 1986, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
//==========================================================================
#include <pkgconf/net.h>
#include <pkgconf/io_fileio.h>
#include <sys/types.h>
#include <cyg/io/file.h>
#include <cyg/fileio/fileio.h>
#include <cyg/fileio/sockio.h>
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/route.h>
//==========================================================================
// Forward definitions
static int bsd_init( cyg_nstab_entry *nste );
static int bsd_socket( cyg_nstab_entry *nste, int domain, int type,
int protocol, cyg_file *file );
static int bsd_bind ( cyg_file *fp, const sockaddr *sa, socklen_t len );
static int bsd_connect ( cyg_file *fp, const sockaddr *sa, socklen_t len );
static int bsd_accept ( cyg_file *fp, cyg_file *new_fp,
struct sockaddr *name, socklen_t *anamelen );
static int bsd_listen ( cyg_file *fp, int len );
static int bsd_getname ( cyg_file *fp, sockaddr *sa, socklen_t *len, int peer );
static int bsd_shutdown ( cyg_file *fp, int flags );
static int bsd_getsockopt( cyg_file *fp, int level, int optname,
void *optval, socklen_t *optlen);
static int bsd_setsockopt( cyg_file *fp, int level, int optname,
const void *optval, socklen_t optlen);
static int bsd_sendmsg ( cyg_file *fp, const struct msghdr *m,
int flags, ssize_t *retsize );
static int bsd_recvmsg ( cyg_file *fp, struct msghdr *m,
socklen_t *namelen, ssize_t *retsize );
// File operations
static int bsd_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int bsd_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int bsd_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
static int bsd_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data);
static int bsd_select (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info);
static int bsd_fsync (struct CYG_FILE_TAG *fp, int mode );
static int bsd_close (struct CYG_FILE_TAG *fp);
static int bsd_fstat (struct CYG_FILE_TAG *fp, struct stat *buf );
static int bsd_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
static int bsd_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
static int
bsd_recvit(cyg_file *fp, struct msghdr *mp, socklen_t *namelenp, ssize_t *retsize);
static int
bsd_sendit(cyg_file *fp, const struct msghdr *mp, int flags, ssize_t *retsize);
//==========================================================================
// Table entrys
NSTAB_ENTRY( bsd_nste, 0,
"bsd_tcpip",
"",
0,
bsd_init,
bsd_socket);
struct cyg_sock_ops bsd_sockops =
{
bsd_bind,
bsd_connect,
bsd_accept,
bsd_listen,
bsd_getname,
bsd_shutdown,
bsd_getsockopt,
bsd_setsockopt,
bsd_sendmsg,
bsd_recvmsg
};
cyg_fileops bsd_sock_fileops =
{
bsd_read,
bsd_write,
bsd_lseek,
bsd_ioctl,
bsd_select,
bsd_fsync,
bsd_close,
bsd_fstat,
bsd_getinfo,
bsd_setinfo
};
//==========================================================================
// NStab functions
// -------------------------------------------------------------------------
static int bsd_init( cyg_nstab_entry *nste )
{
// Initialization already handled via constructor
return ENOERR;
}
// -------------------------------------------------------------------------
static int bsd_socket( cyg_nstab_entry *nste, int domain, int type,
int protocol, cyg_file *file )
{
int error = 0;
struct socket *so;
error = socreate( domain, &so, type, protocol );
if( error == ENOERR )
{
cyg_selinit(&so->so_rcv.sb_sel);
cyg_selinit(&so->so_snd.sb_sel);
file->f_flag |= CYG_FREAD|CYG_FWRITE;
file->f_type = CYG_FILE_TYPE_SOCKET;
file->f_ops = &bsd_sock_fileops;
file->f_offset = 0;
file->f_data = (CYG_ADDRWORD)so;
file->f_xops = (CYG_ADDRWORD)&bsd_sockops;
}
return error;
}
//==========================================================================
// Sockops functions
// -------------------------------------------------------------------------
static int bsd_bind ( cyg_file *fp, const sockaddr *sa, socklen_t len )
{
struct mbuf *nam;
int error;
error = sockargs(&nam, (caddr_t)sa, len, MT_SONAME);
if (error)
return (error);
error = sobind((struct socket *)fp->f_data, nam);
m_freem(nam);
return error;
}
// -------------------------------------------------------------------------
static int bsd_connect ( cyg_file *fp, const sockaddr *sa, socklen_t len )
{
register struct socket *so;
struct mbuf *nam;
int error, s;
so = (struct socket *)fp->f_data;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
return (EALREADY);
error = sockargs(&nam, (caddr_t)sa, len, MT_SONAME);
if (error)
return (error);
error = soconnect(so, nam);
if (error)
goto bad;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
m_freem(nam);
return (EINPROGRESS);
}
s = splsoftnet();
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
netcon, 0);
if (error)
break;
}
if (error == 0) {
error = so->so_error;
so->so_error = 0;
}
splx(s);
bad:
so->so_state &= ~SS_ISCONNECTING;
m_freem(nam);
return error;
}
// -------------------------------------------------------------------------
static int bsd_accept ( cyg_file *fp, cyg_file *new_fp,
struct sockaddr *name, socklen_t *anamelen )
{
struct mbuf *nam;
socklen_t namelen = 0;
int error = 0, s;
register struct socket *so;
if( anamelen != NULL )
namelen = *anamelen;
s = splsoftnet();
so = (struct socket *)fp->f_data;
if ((so->so_options & SO_ACCEPTCONN) == 0) {
splx(s);
return (EINVAL);
}
if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
splx(s);
return (EWOULDBLOCK);
}
while (so->so_qlen == 0 && so->so_error == 0) {
if (so->so_state & SS_CANTRCVMORE) {
so->so_error = ECONNABORTED;
break;
}
error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
netcon, 0);
if (error) {
splx(s);
return (error);
}
}
if (so->so_error) {
error = so->so_error;
so->so_error = 0;
splx(s);
return (error);
}
{
struct socket *aso = so->so_q;
if (soqremque(aso, 1) == 0)
panic("accept");
so = aso;
}
cyg_selinit(&so->so_rcv.sb_sel);
cyg_selinit(&so->so_snd.sb_sel);
new_fp->f_type = DTYPE_SOCKET;
new_fp->f_flag |= FREAD|FWRITE;
new_fp->f_offset = 0;
new_fp->f_ops = &bsd_sock_fileops;
new_fp->f_data = (CYG_ADDRWORD)so;
new_fp->f_xops = (CYG_ADDRWORD)&bsd_sockops;
nam = m_get(M_WAIT, MT_SONAME);
(void) soaccept(so, nam);
if (name) {
if (namelen > nam->m_len)
namelen = nam->m_len;
/* SHOULD COPY OUT A CHAIN HERE */
if ((error = copyout(mtod(nam, caddr_t),
(caddr_t)name, namelen)) == 0)
*anamelen = namelen;
}
m_freem(nam);
splx(s);
return (error);
}
// -------------------------------------------------------------------------
static int bsd_listen ( cyg_file *fp, int backlog )
{
return (solisten((struct socket *)fp->f_data, backlog));
}
// -------------------------------------------------------------------------
static int bsd_getname ( cyg_file *fp, sockaddr *asa, socklen_t *alen, int peer )
{
register struct socket *so;
struct mbuf *m;
socklen_t len = 0;
int error;
int type = peer ? PRU_PEERADDR : PRU_SOCKADDR;
if( alen != NULL )
len = *alen;
so = (struct socket *)fp->f_data;
if ( peer && (so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
return (ENOTCONN);
m = m_getclr(M_WAIT, MT_SONAME);
if (m == NULL)
return (ENOBUFS);
error = (*so->so_proto->pr_usrreq)(so, type, 0, m, 0);
if (error)
goto bad;
if (len > m->m_len)
len = m->m_len;
error = copyout(mtod(m, caddr_t), (caddr_t)asa, len);
if (error == 0)
*alen = len;
bad:
m_freem(m);
return (error);
}
// -------------------------------------------------------------------------
static int bsd_shutdown ( cyg_file *fp, int how )
{
return (soshutdown((struct socket *)fp->f_data, how));
}
// -------------------------------------------------------------------------
static int bsd_getsockopt( cyg_file *fp, int level, int optname,
void *optval, socklen_t *optlen)
{
struct mbuf *m = NULL;
socklen_t valsize = 0;
int error;
if( optval != NULL && optlen != NULL )
valsize = *optlen;
error = sogetopt((struct socket *)fp->f_data, level, optname, &m);
if( error == ENOERR && valsize != 0 && m != NULL)
{
if (valsize > m->m_len)
valsize = m->m_len;
error = copyout(mtod(m, caddr_t), optval, valsize);
if( error == ENOERR )
*optlen = valsize;
}
if (m != NULL)
(void) m_free(m);
return (error);
}
// -------------------------------------------------------------------------
static int bsd_setsockopt( cyg_file *fp, int level, int optname,
const void *optval, socklen_t optlen)
{
int error;
struct mbuf *m = NULL;
if( optlen > MCLBYTES )
return EINVAL;
if (optval != NULL) {
m = m_get(M_WAIT, MT_SOOPTS);
if (optlen > MLEN) {
MCLGET(m, M_DONTWAIT);
if ((m->m_flags & M_EXT) == 0) {
m_freem(m);
return (ENOBUFS);
}
}
if (m == NULL)
return (ENOBUFS);
error = copyin(optval, mtod(m, caddr_t), optlen);
if (error) {
(void) m_free(m);
return (error);
}
m->m_len = optlen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -