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

📄 sockio.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      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 + -