Mercurial > ecos
diff packages/io/fileio/current/src/socket.cxx @ 115:6ed91473a1cd ecos-sw-2000-08-21
Merge from eCos master repository on 2000-08-21-22:40:54-BST
| author | jlarmour |
|---|---|
| date | Fri, 25 Aug 2000 17:32:38 +0000 |
| parents | |
| children | 2395031e7a66 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/io/fileio/current/src/socket.cxx @@ -0,0 +1,725 @@ +//========================================================================== +// +// socket.cxx +// +// Fileio socket operations +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): nickg +// Contributors: nickg +// Date: 2000-05-25 +// Purpose: Fileio socket operations +// Description: These are the functions that operate on sockets, +// such as socket(), bind(), accept() etc. +// +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/system.h> +#include <pkgconf/hal.h> +#include <pkgconf/kernel.h> +#include <pkgconf/io_fileio.h> + +#include <cyg/hal/hal_tables.h> + +#include <cyg/kernel/ktypes.h> // base kernel types +#include <cyg/infra/cyg_trac.h> // tracing macros +#include <cyg/infra/cyg_ass.h> // assertion macros + +#include <stdarg.h> // for fcntl() + +#include <cyg/io/file.h> // struct iovec + +#include "fio.h" // Private header + +#include <cyg/kernel/mutex.hxx> // mutex definitions + +#ifdef CYGPKG_NET + +#include <sys/socket.h> // struct msghdr + +#endif + +//========================================================================== +// Forward definitions + +static void cyg_ns_lock( cyg_nstab_entry *ns ); +static void cyg_ns_unlock( cyg_nstab_entry *ns ); +static void cyg_sock_lock( cyg_file *fp ); +static void cyg_sock_unlock( cyg_file *fp ); + +//========================================================================== +// Local entry/return macros + +#define SOCKET_ENTRY() FILEIO_ENTRY() + +#define SOCKET_RETURN(err) FILEIO_RETURN(err) + +#define SOCKET_RETURN_VALUE(val) FILEIO_RETURN_VALUE(val) + +//========================================================================== +// Locking protocols + +#define LOCK_NS( _n ) cyg_ns_lock( _n ) + +#define UNLOCK_NS( _n ) cyg_ns_unlock( _n ) + +#define LOCK_SOCKET( _fp ) cyg_sock_lock( _fp ) + +#define UNLOCK_SOCKET( _fp ) cyg_sock_unlock( _fp ) + +//========================================================================== +// Tables and local variables + +// Array of network stacks installed +__externC cyg_nstab_entry nstab[]; +CYG_HAL_TABLE_BEGIN( nstab, nstab ); + +// End of array marker +__externC cyg_nstab_entry nstab_end; +CYG_HAL_TABLE_END( nstab_end, nstab ); + +Cyg_Mutex nstab_lock[CYGNUM_FILEIO_NSTAB_MAX]; + +//========================================================================== +// Initialization + +__externC void cyg_nstab_init() +{ + cyg_nstab_entry *n; + + for( n = &nstab[0]; n != &nstab_end; n++ ) + { + // stop if there are more than the configured maximum + if( n-&nstab[0] >= CYGNUM_FILEIO_NSTAB_MAX ) + break; + + if( n->init( n ) == 0 ) + { + n->valid = true; + } + } +} + +//========================================================================== +// Socket API calls + +// ------------------------------------------------------------------------- + +__externC int socket (int domain, int type, int protocol) +{ + SOCKET_ENTRY(); + + int err = 0; + int fd; + cyg_file *file; + + fd = cyg_fd_alloc(0); + + if( fd < 0 ) + SOCKET_RETURN(EMFILE); + + file = cyg_file_alloc(); + + if( file == NULL ) + { + cyg_fd_free(fd); + SOCKET_RETURN(ENFILE); + } + + cyg_nstab_entry *n; + + for( n = &nstab[0]; n != &nstab_end; n++ ) + { + LOCK_NS( n ); + + err = n->socket( n, domain, type, protocol, file ); + + UNLOCK_NS( n ); + + if( err == 0 ) break; + } + + if( err != 0 ) + { + cyg_fd_free(fd); + cyg_file_free(file); + SOCKET_RETURN( err ); + } + + file->f_syncmode = n->syncmode; + file->f_mte = (cyg_mtab_entry *)n; + + cyg_fd_assign( fd, file ); + + SOCKET_RETURN_VALUE(fd); +} + + +// ------------------------------------------------------------------------- + +__externC int accept (int s, struct sockaddr *sa, socklen_t *addrlen) +{ + SOCKET_ENTRY(); + + int err = 0; + int fd; + cyg_file *fp; + cyg_file *new_fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + fd = cyg_fd_alloc(0); + + if( fd < 0 ) + { + cyg_fp_free( fp ); + SOCKET_RETURN(EMFILE); + } + + new_fp = cyg_file_alloc(); + + if( new_fp == NULL ) + { + cyg_fp_free( fp ); + cyg_fd_free(fd); + SOCKET_RETURN(ENFILE); + } + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + err = ops->accept( fp, new_fp, sa, addrlen ); + + UNLOCK_SOCKET( fp ); + + } + else err = EBADF; + + if( err != 0 ) + { + cyg_fp_free( fp ); + cyg_fd_free(fd); + cyg_file_free(new_fp); + SOCKET_RETURN( err ); + } + + new_fp->f_syncmode = fp->f_syncmode; + new_fp->f_mte = fp->f_mte; + + cyg_fd_assign( fd, new_fp ); + + cyg_fp_free( fp ); + + SOCKET_RETURN_VALUE(fd); +} + + +// ------------------------------------------------------------------------- + +__externC int bind (int s, const struct sockaddr *sa, unsigned int len) +{ + SOCKET_ENTRY(); + + int ret = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + ret = ops->bind( fp, sa, len ); + + UNLOCK_SOCKET( fp ); + + } + + cyg_fp_free( fp ); + + SOCKET_RETURN(ret); +} + + +// ------------------------------------------------------------------------- + +__externC int connect (int s, const struct sockaddr *sa, socklen_t len) +{ + SOCKET_ENTRY(); + + int ret = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + ret = ops->connect( fp, sa, len ); + + UNLOCK_SOCKET( fp ); + + } + + cyg_fp_free( fp ); + + SOCKET_RETURN(ret); +} + + +// ------------------------------------------------------------------------- + +__externC int getpeername (int s, struct sockaddr *sa, socklen_t *len) +{ + SOCKET_ENTRY(); + + int ret = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + ret = ops->getname( fp, sa, len, 1 ); + + UNLOCK_SOCKET( fp ); + } + + cyg_fp_free( fp ); + + SOCKET_RETURN(ret); +} + + +// ------------------------------------------------------------------------- + +__externC int getsockname (int s, struct sockaddr *sa, socklen_t *len) +{ + SOCKET_ENTRY(); + + int ret = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + ret = ops->getname( fp, sa, len, 0 ); + + UNLOCK_SOCKET( fp ); + } + + cyg_fp_free( fp ); + + SOCKET_RETURN(ret); +} + + +// ------------------------------------------------------------------------- + +__externC int getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen) +{ + SOCKET_ENTRY(); + + int ret = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + ret = ops->getsockopt( fp, level, optname, optval, optlen ); + + UNLOCK_SOCKET( fp ); + } + + cyg_fp_free( fp ); + + SOCKET_RETURN(ret); +} + + +// ------------------------------------------------------------------------- + +__externC int listen (int s, int len) +{ + SOCKET_ENTRY(); + + int ret = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + ret = ops->listen( fp, len ); + + UNLOCK_SOCKET( fp ); + } + + cyg_fp_free( fp ); + + SOCKET_RETURN(ret); +} + + +// ------------------------------------------------------------------------- + +__externC ssize_t recvmsg (int s, struct msghdr *msg, int flags) +{ + SOCKET_ENTRY(); + + ssize_t ret = 0; + int error = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + msg->msg_flags = flags; + + error = ops->recvmsg( fp, msg, NULL, &ret ); + + UNLOCK_SOCKET( fp ); + } + + cyg_fp_free( fp ); + + if( error != ENOERR ) + SOCKET_RETURN(error); + + SOCKET_RETURN_VALUE( ret ); +} + +// ------------------------------------------------------------------------- + +__externC ssize_t recvfrom (int s, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + SOCKET_ENTRY(); + + struct msghdr msg; + struct iovec iov; + ssize_t ret = 0; + int error = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + // Set up a message header... + msg.msg_name = (caddr_t)from; + msg.msg_namelen = *fromlen; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + iov.iov_base = buf; + iov.iov_len = len; + msg.msg_control = 0; + msg.msg_flags = flags; + + LOCK_SOCKET( fp ); + + error = ops->recvmsg( fp, &msg, fromlen, &ret ); + + UNLOCK_SOCKET( fp ); + } + + cyg_fp_free( fp ); + + if( error != ENOERR ) + SOCKET_RETURN(error); + + SOCKET_RETURN_VALUE( ret ); + +} + +// ------------------------------------------------------------------------- + +__externC ssize_t recv (int s, void *buf, size_t len, int flags) +{ + return recvfrom( s, buf, len, flags, NULL, NULL ); +} + +// ------------------------------------------------------------------------- + +__externC ssize_t sendmsg (int s, const struct msghdr *msg, int flags) +{ + SOCKET_ENTRY(); + + ssize_t ret = 0; + int error = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + error = ops->sendmsg( fp, msg, flags, &ret ); + + UNLOCK_SOCKET( fp ); + } + + cyg_fp_free( fp ); + + if( error != ENOERR ) + SOCKET_RETURN(error); + + SOCKET_RETURN_VALUE( ret ); +} + + +// ------------------------------------------------------------------------- + +__externC ssize_t sendto (int s, const void *buf, + size_t len, int flags, const struct sockaddr *to, socklen_t tolen) +{ + SOCKET_ENTRY(); + + ssize_t ret = 0; + int error = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + + struct msghdr msg; + struct iovec iov; + + msg.msg_name = (caddr_t)to; + msg.msg_namelen = tolen; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = 0; + msg.msg_flags = 0; + iov.iov_base = (char *)buf; + iov.iov_len = len; + + LOCK_SOCKET( fp ); + + error = ops->sendmsg( fp, &msg, flags, &ret ); + + UNLOCK_SOCKET( fp ); + } + + cyg_fp_free( fp ); + + if( error != ENOERR ) + SOCKET_RETURN(error); + + SOCKET_RETURN_VALUE( ret ); +} + +// ------------------------------------------------------------------------- + +__externC ssize_t send (int s, const void *buf, size_t len, int flags) +{ + return sendto( s, buf, len, flags, NULL, 0 ); +} + + +// ------------------------------------------------------------------------- + +__externC int setsockopt (int s, int level, int optname, + const void *optval, socklen_t optlen) +{ + SOCKET_ENTRY(); + + int ret = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + ret = ops->setsockopt( fp, level, optname, optval, optlen ); + + UNLOCK_SOCKET( fp ); + } + + cyg_fp_free( fp ); + + SOCKET_RETURN(ret); +} + +// ------------------------------------------------------------------------- + +__externC int shutdown (int s, int how) +{ + SOCKET_ENTRY(); + + int ret = 0; + cyg_file *fp; + + fp = cyg_fp_get( s ); + + if( fp == NULL ) + FILEIO_RETURN(EBADF); + + if( fp->f_type == CYG_FILE_TYPE_SOCKET ) + { + cyg_sock_ops *ops = (cyg_sock_ops *)fp->f_xops; + + LOCK_SOCKET( fp ); + + ret = ops->shutdown( fp, how ); + + UNLOCK_SOCKET( fp ); + } + + cyg_fp_free( fp ); + + SOCKET_RETURN(ret); +} + +//========================================================================== +// Locking protocol + +static void cyg_ns_lock( cyg_nstab_entry *ns ) +{ + if( ns->syncmode & CYG_SYNCMODE_SOCK_NETSTACK ) + { + nstab_lock[ns-&nstab[0]].lock(); + } +} + +static void cyg_ns_unlock( cyg_nstab_entry *ns ) +{ + if( ns->syncmode & CYG_SYNCMODE_SOCK_NETSTACK ) + { + nstab_lock[ns-&nstab[0]].unlock(); + } +} + +static void cyg_sock_lock( cyg_file *fp ) +{ + cyg_nstab_entry *ns = (cyg_nstab_entry *)fp->f_mte; + + if( fp->f_syncmode & CYG_SYNCMODE_SOCK_NETSTACK ) + nstab_lock[ns-&nstab[0]].lock(); + + cyg_file_lock( fp, fp->f_syncmode>>CYG_SYNCMODE_SOCK_SHIFT); +} + +static void cyg_sock_unlock( cyg_file *fp ) +{ + cyg_nstab_entry *ns = (cyg_nstab_entry *)fp->f_mte; + + if( fp->f_syncmode & CYG_SYNCMODE_SOCK_NETSTACK ) + nstab_lock[ns-&nstab[0]].unlock(); + + cyg_file_lock( fp, fp->f_syncmode>>CYG_SYNCMODE_SOCK_SHIFT); +} + + +// ------------------------------------------------------------------------- +// EOF socket.cxx
