sockio.c
来自「嵌入式操作系统ECOS的网络开发包」· C语言 代码 · 共 1,071 行 · 第 1/2 页
C
1,071 行
//==========================================================================
//
// src/sys/kern/sockio.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//==========================================================================
//
// 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, gthomas
// Date: 2000-06-06
// Purpose:
// Description: File I/O operations for network sockets. Ruthelessly
// cribbed from the BSD sources and adapted to eCos.
//
//####DESCRIPTIONEND####
//
//==========================================================================
/*
* Copyright (c) 1982, 1986, 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* sendfile(2) and related extensions:
* Copyright (c) 1998, David Greenman. All rights reserved.
*
* 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.
*
* @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94
* $FreeBSD: src/sys/kern/uipc_syscalls.c,v 1.65.2.9 2001/07/31 10:49:39 dwmalone Exp $
*/
//==========================================================================
#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/malloc.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);
static int getsockaddr (struct sockaddr **namp, caddr_t uaddr, size_t len);
//==========================================================================
// 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, (struct proc *)&proc0);
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)
{
int error;
error = sobind((struct socket *)fp->f_data, (sockaddr *)sa, 0);
return error;
}
// -------------------------------------------------------------------------
static int
bsd_connect(cyg_file *fp, const sockaddr *sa, socklen_t len)
{
struct socket *so;
int error, s;
so = (struct socket *)fp->f_data;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
return (EALREADY);
error = soconnect(so, (struct sockaddr *)sa, 0);
if (error)
goto bad;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
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;
return error;
}
// -------------------------------------------------------------------------
static int
bsd_accept(cyg_file *fp, cyg_file *new_fp,
struct sockaddr *name, socklen_t *anamelen)
{
socklen_t namelen = 0;
int error = 0, s;
struct socket *head, *so;
struct sockaddr *sa;
if( anamelen != NULL)
namelen = *anamelen;
s = splsoftnet();
head = (struct socket *)fp->f_data;
if ((head->so_options & SO_ACCEPTCONN) == 0) {
splx(s);
return (EINVAL);
}
if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) {
splx(s);
return (EWOULDBLOCK);
}
while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) {
if (head->so_state & SS_CANTRCVMORE) {
head->so_error = ECONNABORTED;
break;
}
error = tsleep((caddr_t)&head->so_timeo, PSOCK | PCATCH,
"netcon", 0);
if (error) {
splx(s);
return (error);
}
}
if (head->so_error) {
error = head->so_error;
head->so_error = 0;
splx(s);
return (error);
}
/*
* At this point we know that there is at least one connection
* ready to be accepted. Remove it from the queue prior to
* allocating the file descriptor for it since falloc() may
* block allowing another process to accept the connection
* instead.
*/
so = TAILQ_FIRST(&head->so_comp);
TAILQ_REMOVE(&head->so_comp, so, so_list);
head->so_qlen--;
#if 0 // FIXME
fflag = lfp->f_flag;
error = falloc(p, &nfp, &fd);
if (error) {
/*
* Probably ran out of file descriptors. Put the
* unaccepted connection back onto the queue and
* do another wakeup so some other process might
* have a chance at it.
*/
TAILQ_INSERT_HEAD(&head->so_comp, so, so_list);
head->so_qlen++;
wakeup_one(&head->so_timeo);
splx(s);
goto done;
}
fhold(nfp);
p->p_retval[0] = fd;
/* connection has been removed from the listen queue */
KNOTE(&head->so_rcv.sb_sel.si_note, 0);
#endif
so->so_state &= ~SS_COMP;
so->so_head = NULL;
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;
sa = 0;
error = soaccept(so, &sa);
if (error) {
/*
* return a namelen of zero for older code which might
* ignore the return value from accept.
*/
if (name != NULL) {
*anamelen = 0;
}
goto noconnection;
}
if (sa == NULL) {
namelen = 0;
if (name)
goto gotnoname;
splx(s);
error = 0;
goto done;
}
if (name) {
if (namelen > sa->sa_len)
namelen = sa->sa_len;
#ifdef COMPAT_OLDSOCK
if (compat)
((struct osockaddr *)sa)->sa_family = sa->sa_family;
#endif
error = copyout(sa, (caddr_t)name, namelen);
if (!error)
gotnoname:
*anamelen = namelen;
}
noconnection:
#if 0 // FIXME
/*
* close the new descriptor, assuming someone hasn't ripped it
* out from under us.
*/
if (error) {
if (fdp->fd_ofiles[fd] == nfp) {
fdp->fd_ofiles[fd] = NULL;
fdrop(nfp, p);
}
}
splx(s);
/*
* Release explicitly held references before returning.
*/
done:
if (nfp != NULL)
fdrop(nfp, p);
fdrop(lfp, p);
return (error);
m_freem(nam);
#else
done:
#endif
splx(s);
return (error);
}
// -------------------------------------------------------------------------
static int
bsd_listen(cyg_file *fp, int backlog)
{
return (solisten((struct socket *)fp->f_data, backlog, 0));
}
// -------------------------------------------------------------------------
static int
bsd_getname(cyg_file *fp, sockaddr *asa, socklen_t *alen, int peer)
{
struct socket *so;
socklen_t len = 0;
int error;
sockaddr *sa;
if( alen != NULL)
len = *alen;
so = (struct socket *)fp->f_data;
sa = 0;
if (peer) {
// getpeername()
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
return (ENOTCONN);
}
error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &sa);
} else {
// getsockname()
error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa);
}
if (error)
goto bad;
if (sa == 0) {
len = 0;
goto gotnothing;
}
len = min(len, sa->sa_len);
#ifdef COMPAT_OLDSOCK
if (compat)
((struct osockaddr *)sa)->sa_family = sa->sa_family;
#endif
error = copyout(sa, (caddr_t)asa, (u_int)len);
gotnothing:
*alen = len;
bad:
if (sa)
FREE(sa, M_SONAME);
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)
{
socklen_t valsize = 0;
int error;
struct sockopt opt;
if( optval != NULL && optlen != NULL)
valsize = *optlen;
opt.sopt_dir = SOPT_GET;
opt.sopt_level = level;
opt.sopt_name = optname;
opt.sopt_val = optval;
opt.sopt_valsize = valsize;
opt.sopt_p = 0;
error = sogetopt((struct socket *)fp->f_data, &opt);
if (error == 0) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?