From 23f14c2660e87e1d5a456767cc7165a3864319d5 Mon Sep 17 00:00:00 2001 From: dongjianli Date: Sun, 26 Aug 2018 15:15:48 -0600 Subject: [PATCH] net/usrsock: Add the listen/accept/getpeername/ioctl support --- include/nuttx/net/usrsock.h | 37 +++ net/usrsock/Make.defs | 3 +- net/usrsock/usrsock.h | 114 +++++++ net/usrsock/usrsock_accept.c | 486 ++++++++++++++++++++++++++++++ net/usrsock/usrsock_getpeername.c | 243 +++++++++++++++ net/usrsock/usrsock_ioctl.c | 225 ++++++++++++++ net/usrsock/usrsock_listen.c | 241 +++++++++++++++ net/usrsock/usrsock_sockif.c | 100 +----- 8 files changed, 1353 insertions(+), 96 deletions(-) create mode 100644 net/usrsock/usrsock_accept.c create mode 100644 net/usrsock/usrsock_getpeername.c create mode 100644 net/usrsock/usrsock_ioctl.c create mode 100644 net/usrsock/usrsock_listen.c diff --git a/include/nuttx/net/usrsock.h b/include/nuttx/net/usrsock.h index 0e20d3c5a2..ddf07d3ffc 100644 --- a/include/nuttx/net/usrsock.h +++ b/include/nuttx/net/usrsock.h @@ -90,7 +90,11 @@ enum usrsock_request_types_e USRSOCK_REQUEST_SETSOCKOPT, USRSOCK_REQUEST_GETSOCKOPT, USRSOCK_REQUEST_GETSOCKNAME, + USRSOCK_REQUEST_GETPEERNAME, USRSOCK_REQUEST_BIND, + USRSOCK_REQUEST_LISTEN, + USRSOCK_REQUEST_ACCEPT, + USRSOCK_REQUEST_IOCTL, USRSOCK_REQUEST__MAX }; @@ -143,6 +147,22 @@ begin_packed_struct struct usrsock_request_connect_s uint16_t addrlen; } end_packed_struct; +begin_packed_struct struct usrsock_request_listen_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + uint16_t backlog; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_accept_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + uint16_t max_addrlen; +} end_packed_struct; + begin_packed_struct struct usrsock_request_sendto_s { struct usrsock_request_common_s head; @@ -189,6 +209,23 @@ begin_packed_struct struct usrsock_request_getsockname_s uint16_t max_addrlen; } end_packed_struct; +begin_packed_struct struct usrsock_request_getpeername_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + uint16_t max_addrlen; +} end_packed_struct; + +begin_packed_struct struct usrsock_request_ioctl_s +{ + struct usrsock_request_common_s head; + + int16_t usockid; + int32_t cmd; + uint16_t arglen; +} end_packed_struct; + /* Response/event message structures (kernel <= /dev/usrsock <= daemon) */ begin_packed_struct struct usrsock_message_common_s diff --git a/net/usrsock/Make.defs b/net/usrsock/Make.defs index 4338f7201e..cf8d7f651f 100644 --- a/net/usrsock/Make.defs +++ b/net/usrsock/Make.defs @@ -38,10 +38,11 @@ ifeq ($(CONFIG_NET_USRSOCK),y) NET_CSRCS += usrsock_close.c usrsock_conn.c usrsock_bind.c usrsock_connect.c -NET_CSRCS += usrsock_dev.c +NET_CSRCS += usrsock_dev.c usrsock_getpeername.c NET_CSRCS += usrsock_event.c usrsock_getsockname.c usrsock_getsockopt.c NET_CSRCS += usrsock_poll.c usrsock_recvfrom.c usrsock_sendto.c NET_CSRCS += usrsock_setsockopt.c usrsock_socket.c usrsock_sockif.c +NET_CSRCS += usrsock_accept.c usrsock_listen.c usrsock_ioctl.c # Include User Socket build support diff --git a/net/usrsock/usrsock.h b/net/usrsock/usrsock.h index 80030795f3..44629a80f0 100644 --- a/net/usrsock/usrsock.h +++ b/net/usrsock/usrsock.h @@ -403,6 +403,80 @@ int usrsock_bind(FAR struct socket *psock, int usrsock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); +/**************************************************************************** + * Name: usrsock_listen + * + * Description: + * To accept connections, a socket is first created with psock_socket(), a + * willingness to accept incoming connections and a queue limit for + * incoming connections are specified with psock_listen(), and then the + * connections are accepted with psock_accept(). For the case of AFINET + * and AFINET6 sockets, psock_listen() calls this function. The + * psock_listen() call applies only to sockets of type SOCK_STREAM or + * SOCK_SEQPACKET. + * + * Parameters: + * psock Reference to an internal, bound socket structure. + * backlog The maximum length the queue of pending connections may grow. + * If a connection request arrives with the queue full, the client + * may receive an error with an indication of ECONNREFUSED or, + * if the underlying protocol supports retransmission, the request + * may be ignored so that retries succeed. + * + * Returned Value: + * On success, zero is returned. On error, a negated errno value is + * returned. See list() for the set of appropriate error values. + * + ****************************************************************************/ + +int usrsock_listen(FAR struct socket *psock, int backlog); + +/**************************************************************************** + * Name: usrsock_accept + * + * Description: + * The usrsock_sockif_accept function is used with connection-based socket + * types (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first + * connection request on the queue of pending connections, creates a new + * connected socket with mostly the same properties as 'sockfd', and + * allocates a new socket descriptor for the socket, which is returned. The + * newly created socket is no longer in the listening state. The original + * socket 'sockfd' is unaffected by this call. Per file descriptor flags + * are not inherited across an inet_accept. + * + * The 'sockfd' argument is a socket descriptor that has been created with + * socket(), bound to a local address with bind(), and is listening for + * connections after a call to listen(). + * + * On return, the 'addr' structure is filled in with the address of the + * connecting entity. The 'addrlen' argument initially contains the size + * of the structure pointed to by 'addr'; on return it will contain the + * actual length of the address returned. + * + * If no pending connections are present on the queue, and the socket is + * not marked as non-blocking, inet_accept blocks the caller until a + * connection is present. If the socket is marked non-blocking and no + * pending connections are present on the queue, inet_accept returns + * EAGAIN. + * + * Parameters: + * psock Reference to the listening socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newsock Location to return the accepted socket information. + * + * Returned Value: + * Returns 0 (OK) on success. On failure, it returns a negated errno + * value. See accept() for a desrciption of the approriate error value. + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +int usrsock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock); + /**************************************************************************** * Name: usrsock_poll * @@ -557,6 +631,46 @@ int usrsock_setsockopt(FAR struct usrsock_conn_s *conn, int level, int option, int usrsock_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen); +/**************************************************************************** + * Name: usrsock_getpeername + * + * Description: + * The getpeername() function retrieves the remote-connected name of the + * specified socket, stores this address in the sockaddr structure pointed + * to by the 'addr' argument, and stores the length of this address in the + * object pointed to by the 'addrlen' argument. + * + * If the actual length of the address is greater than the length of the + * supplied sockaddr structure, the stored address will be truncated. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Input Parameters: + * conn usrsock socket connection structure + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + ****************************************************************************/ + +int usrsock_getpeername(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR socklen_t *addrlen); + +/**************************************************************************** + * Name: usrsock_ioctl + * + * Description: + * The usrsock_ioctl() function performs network device specific operations. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * cmd The ioctl command + * arg The argument of the ioctl cmd + * + ****************************************************************************/ + +int usrsock_ioctl(FAR struct socket *psock, int cmd, FAR void *arg, size_t arglen); + #undef EXTERN #ifdef __cplusplus } diff --git a/net/usrsock/usrsock_accept.c b/net/usrsock/usrsock_accept.c new file mode 100644 index 0000000000..11943afbe3 --- /dev/null +++ b/net/usrsock/usrsock_accept.c @@ -0,0 +1,486 @@ +/**************************************************************************** + * net/usrsock/usrsock_accept.c + * + * Copyright (C) 2018 Pinecone Inc. All rights reserved. + * Author: Xiang Xiao + * + * 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. Neither the name NuttX 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include + +#include +#include +#include + +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t accept_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_data_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->reqstate.result = -ECONNABORTED; + pstate->valuelen = 0; + pstate->valuelen_nontrunc = 0; + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->reqstate.recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->reqstate.result = conn->resp.result; + if (pstate->reqstate.result < 0) + { + pstate->valuelen = 0; + pstate->valuelen_nontrunc = 0; + } + else + { + pstate->valuelen = conn->resp.valuelen; + pstate->valuelen_nontrunc = conn->resp.valuelen_nontrunc; + } + + if (pstate->reqstate.result >= 0 || + pstate->reqstate.result == -EAGAIN) + { + /* After reception of connection, mark input not ready. Daemon will + * send event to restore this flag. */ + + conn->flags &= ~USRSOCK_EVENT_RECVFROM_AVAIL; + } + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->reqstate.recvsem); + } + else if (flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ninfo("remote closed.\n"); + + pstate->reqstate.result = -EPIPE; + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->reqstate.recvsem); + } + else if (flags & USRSOCK_EVENT_RECVFROM_AVAIL) + { + ninfo("accept avail.\n"); + + flags &= ~USRSOCK_EVENT_RECVFROM_AVAIL; + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->reqstate.recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_accept_request + ****************************************************************************/ + +static int do_accept_request(FAR struct usrsock_conn_s *conn, socklen_t addrlen) +{ + struct usrsock_request_accept_s req = {}; + struct iovec bufs[1]; + + if (addrlen > UINT16_MAX) + { + addrlen = UINT16_MAX; + } + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_ACCEPT; + req.usockid = conn->usockid; + req.max_addrlen = addrlen; + + bufs[0].iov_base = &req; + bufs[0].iov_len = sizeof(req); + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsock_accept + * + * Description: + * The usrsock_sockif_accept function is used with connection-based socket + * types (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first + * connection request on the queue of pending connections, creates a new + * connected socket with mostly the same properties as 'sockfd', and + * allocates a new socket descriptor for the socket, which is returned. The + * newly created socket is no longer in the listening state. The original + * socket 'sockfd' is unaffected by this call. Per file descriptor flags + * are not inherited across an inet_accept. + * + * The 'sockfd' argument is a socket descriptor that has been created with + * socket(), bound to a local address with bind(), and is listening for + * connections after a call to listen(). + * + * On return, the 'addr' structure is filled in with the address of the + * connecting entity. The 'addrlen' argument initially contains the size + * of the structure pointed to by 'addr'; on return it will contain the + * actual length of the address returned. + * + * If no pending connections are present on the queue, and the socket is + * not marked as non-blocking, inet_accept blocks the caller until a + * connection is present. If the socket is marked non-blocking and no + * pending connections are present on the queue, inet_accept returns + * EAGAIN. + * + * Parameters: + * psock Reference to the listening socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newsock Location to return the accepted socket information. + * + * Returned Value: + * Returns 0 (OK) on success. On failure, it returns a negated errno + * value. See accept() for a description of the appropriate error value. + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +int usrsock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock) +{ + FAR struct usrsock_conn_s *conn = psock->s_conn; + struct usrsock_data_reqstate_s state = {}; + FAR struct usrsock_conn_s *newconn; + struct iovec inbufs[2]; + socklen_t inaddrlen = 0; + socklen_t outaddrlen = 0; + int ret; +#ifdef CONFIG_NET_SOCKOPTS + struct timespec abstime; +#endif + struct timespec *ptimeo = NULL; + + DEBUGASSERT(conn); + + if (addrlen) + { + if (*addrlen > 0 && addr == NULL) + { + return -EINVAL; + } + + inaddrlen = *addrlen; + } + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; accept() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; + goto errout_unlock; + } + + if (conn->state == USRSOCK_CONN_STATE_CONNECTING) + { + /* Connecting. */ + + ninfo("usockid=%d; socket still connecting.\n", + conn->usockid); + + ret = -EAGAIN; + goto errout_unlock; + } + + if (!conn->connected) + { + /* Not connected. */ + + ninfo("usockid=%d; socket not connected.\n", + conn->usockid); + + ret = -ENOTCONN; + goto errout_unlock; + } + + /* Allocate the usrsock socket connection structure and save in the new + * socket instance. + */ + + newconn = usrsock_alloc(); + if (!newconn) + { + /* Failed to reserve a connection structure */ + + ret = -ENOMEM; + goto errout_unlock; + } + +#ifdef CONFIG_NET_SOCKOPTS + if (psock->s_rcvtimeo != 0) + { + DEBUGVERIFY(clock_gettime(CLOCK_REALTIME, &abstime)); + + /* Prepare timeout value for accept. */ + + abstime.tv_sec += psock->s_rcvtimeo / DSEC_PER_SEC; + abstime.tv_nsec += (psock->s_rcvtimeo % DSEC_PER_SEC) * NSEC_PER_DSEC; + if (abstime.tv_nsec >= NSEC_PER_SEC) + { + abstime.tv_sec++; + abstime.tv_nsec -= NSEC_PER_SEC; + } + + ptimeo = &abstime; + } +#endif + + do + { + /* Check if remote end has closed connection. */ + + if (conn->flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ninfo("usockid=%d; remote closed (EOF).\n", conn->usockid); + + ret = -EPIPE; + goto errout_free_conn; + } + + /* Check if need to wait for connection to become available. */ + + if (!(conn->flags & USRSOCK_EVENT_RECVFROM_AVAIL)) + { + if (_SS_ISNONBLOCK(psock->s_flags)) + { + /* Nothing to receive from daemon side. */ + + ret = -EAGAIN; + goto errout_free_conn; + } + + /* Wait accept to become avail. */ + + ret = usrsock_setup_data_request_callback( + conn, &state, accept_event, + USRSOCK_EVENT_ABORT | USRSOCK_EVENT_RECVFROM_AVAIL | + USRSOCK_EVENT_REMOTE_CLOSED); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_free_conn; + } + + /* Wait for receive-avail (or abort, or timeout, or signal). */ + + ret = net_timedwait(&state.reqstate.recvsem, ptimeo); + if (ret < 0) + { + if (ret == -ETIMEDOUT) + { + ninfo("accept timedout\n"); + + ret = -EAGAIN; + } + else if (ret == -EINTR) + { + ninfo("accept interrupted\n"); + } + else + { + nerr("net_timedwait errno: %d\n", ret); + DEBUGASSERT(false); + } + } + + usrsock_teardown_data_request_callback(&state); + + /* Did wait timeout or got signal? */ + + if (ret != 0) + { + goto errout_free_conn; + } + + /* Was socket aborted? */ + + if (conn->state == USRSOCK_CONN_STATE_ABORTED) + { + ret = -EPIPE; + goto errout_free_conn; + } + + /* Did remote disconnect? */ + + if (conn->flags & USRSOCK_EVENT_REMOTE_CLOSED) + { + ret = -EPIPE; + goto errout_free_conn; + } + + DEBUGASSERT(conn->flags & USRSOCK_EVENT_RECVFROM_AVAIL); + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_data_request_callback( + conn, &state, accept_event, + USRSOCK_EVENT_ABORT | USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_free_conn; + } + + inbufs[0].iov_base = addr; + inbufs[0].iov_len = inaddrlen; + inbufs[1].iov_base = &newconn->usockid; + inbufs[1].iov_len = sizeof(newconn->usockid); + + usrsock_setup_datain(conn, inbufs, ARRAY_SIZE(inbufs)); + + /* Request user-space daemon to accept socket. */ + + ret = do_accept_request(conn, inaddrlen); + if (ret >= 0) + { + /* Wait for completion of request. */ + + while ((ret = net_lockedwait(&state.reqstate.recvsem)) < 0) + { + DEBUGASSERT(ret == -EINTR); + } + + ret = state.reqstate.result; + + DEBUGASSERT(state.valuelen <= inaddrlen); + DEBUGASSERT(state.valuelen <= state.valuelen_nontrunc); + + if (ret >= 0) + { + newconn->state = USRSOCK_CONN_STATE_READY; + newconn->connected = true; + newconn->type = conn->type; + newconn->crefs = 1; + + newsock->s_type = psock->s_type; + newsock->s_domain = psock->s_domain; + newsock->s_conn = newconn; + newsock->s_sockif = psock->s_sockif; + + /* Store length of 'from' address that was available at + * daemon-side. */ + + outaddrlen = state.valuelen_nontrunc; + + ret = OK; + } + } + + usrsock_teardown_datain(conn); + usrsock_teardown_data_request_callback(&state); + } + while (ret == -EAGAIN); + + if (ret >= 0) + { + goto errout_unlock; + } + +errout_free_conn: + usrsock_free(newconn); + +errout_unlock: + net_unlock(); + + if (addrlen) + { + *addrlen = outaddrlen; + } + + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_getpeername.c b/net/usrsock/usrsock_getpeername.c new file mode 100644 index 0000000000..cb13ab377f --- /dev/null +++ b/net/usrsock/usrsock_getpeername.c @@ -0,0 +1,243 @@ +/**************************************************************************** + * net/usrsock/usrsock_getpeername.c + * + * Copyright (C) 2017 Pinecone Inc. All rights reserved. + * Author: Guiding Li + * + * 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. Neither the name NuttX 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t getpeername_event(FAR struct net_driver_s *dev, + FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_data_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->reqstate.result = -ECONNABORTED; + pstate->valuelen = 0; + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->reqstate.recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->reqstate.result = conn->resp.result; + if (pstate->reqstate.result < 0) + { + pstate->valuelen = 0; + pstate->valuelen_nontrunc = 0; + } + else + { + pstate->valuelen = conn->resp.valuelen; + pstate->valuelen_nontrunc = conn->resp.valuelen_nontrunc; + } + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->reqstate.recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_getsockopt_request + ****************************************************************************/ + +static int do_getpeername_request(FAR struct usrsock_conn_s *conn, + socklen_t addrlen) +{ + struct usrsock_request_getpeername_s req = {}; + struct iovec bufs[1]; + + if (addrlen > UINT16_MAX) + { + addrlen = UINT16_MAX; + } + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_GETPEERNAME; + req.usockid = conn->usockid; + req.max_addrlen = addrlen; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsock_getpeername + * + * Description: + * The getpeername() function retrieves the remote-connected name of the + * specified socket, stores this address in the sockaddr structure pointed + * to by the 'addr' argument, and stores the length of this address in the + * object pointed to by the 'addrlen' argument. + * + * If the actual length of the address is greater than the length of the + * supplied sockaddr structure, the stored address will be truncated. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Parameters: + * conn usrsock socket connection structure + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + ****************************************************************************/ + +int usrsock_getpeername(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR socklen_t *addrlen) +{ + FAR struct usrsock_conn_s *conn = psock->s_conn; + struct usrsock_data_reqstate_s state = {}; + struct iovec inbufs[1]; + ssize_t ret; + socklen_t outaddrlen = 0; + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; usrsock_getpeername() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; + goto errout_unlock; + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_data_request_callback( + conn, &state, getpeername_event, + USRSOCK_EVENT_ABORT | USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_unlock; + } + + inbufs[0].iov_base = (FAR void *)addr; + inbufs[0].iov_len = *addrlen; + + usrsock_setup_datain(conn, inbufs, ARRAY_SIZE(inbufs)); + + /* Request user-space daemon to close socket. */ + + ret = do_getpeername_request(conn, *addrlen); + if (ret >= 0) + { + /* Wait for completion of request. */ + + while ((ret = net_lockedwait(&state.reqstate.recvsem)) < 0) + { + DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); + } + + ret = state.reqstate.result; + + DEBUGASSERT(state.valuelen <= *addrlen); + DEBUGASSERT(state.valuelen <= state.valuelen_nontrunc); + + if (ret >= 0) + { + /* Store length of data that was written to 'value' buffer. */ + + outaddrlen = state.valuelen_nontrunc; + } + } + + usrsock_teardown_datain(conn); + usrsock_teardown_data_request_callback(&state); + +errout_unlock: + net_unlock(); + + *addrlen = outaddrlen; + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_ioctl.c b/net/usrsock/usrsock_ioctl.c new file mode 100644 index 0000000000..9b24d818b2 --- /dev/null +++ b/net/usrsock/usrsock_ioctl.c @@ -0,0 +1,225 @@ +/**************************************************************************** + * nuttx/net/usrsock/usrsock_ioctl.c + * + * Copyright (C) 2017 Pinecone Inc. All rights reserved. + * Author: Jianli Dong + * + * 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. Neither the name NuttX 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t ioctl_event(FAR struct net_driver_s *dev, + FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_data_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->reqstate.result = -ECONNABORTED; + pstate->valuelen = 0; + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->reqstate.recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->reqstate.result = conn->resp.result; + if (pstate->reqstate.result < 0) + { + pstate->valuelen = 0; + pstate->valuelen_nontrunc = 0; + } + else + { + pstate->valuelen = conn->resp.valuelen; + pstate->valuelen_nontrunc = conn->resp.valuelen_nontrunc; + } + + /* Stop further callbacks */ + + pstate->reqstate.cb->flags = 0; + pstate->reqstate.cb->priv = NULL; + pstate->reqstate.cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->reqstate.recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_ioctl_request + ****************************************************************************/ + +static int do_ioctl_request(FAR struct usrsock_conn_s *conn, int cmd, + FAR void *arg, size_t arglen) +{ + struct usrsock_request_ioctl_s req = {}; + struct iovec bufs[2]; + + if (arglen > UINT16_MAX) + { + arglen = UINT16_MAX; + } + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_IOCTL; + req.usockid = conn->usockid; + req.cmd = cmd; + req.arglen = arglen; + + bufs[0].iov_base = (FAR void *)&req; + bufs[0].iov_len = sizeof(req); + bufs[1].iov_base = (FAR void *)arg; + bufs[1].iov_len = req.arglen; + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsock_ioctl + * + * Description: + * The usrsock_ioctl() function performs network device specific operations. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * cmd The ioctl command + * arg The argument of the ioctl cmd + * + ****************************************************************************/ + +int usrsock_ioctl(FAR struct socket *psock, int cmd, FAR void *arg, size_t arglen) +{ + FAR struct usrsock_conn_s *conn = psock->s_conn; + struct usrsock_data_reqstate_s state = {}; + struct iovec inbufs[1]; + int ret; + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; ioctl() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; + goto errout_unlock; + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_data_request_callback( + conn, &state, ioctl_event, + USRSOCK_EVENT_ABORT | USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + goto errout_unlock; + } + + inbufs[0].iov_base = arg; + inbufs[0].iov_len = arglen; + usrsock_setup_datain(conn, inbufs, ARRAY_SIZE(inbufs)); + + /* Request user-space daemon to close socket. */ + + ret = do_ioctl_request(conn, cmd, arg, arglen); + if (ret >= 0) + { + /* Wait for completion of request. */ + + while ((ret = net_lockedwait(&state.reqstate.recvsem)) < 0) + { + DEBUGASSERT(ret == -EINTR); + } + + ret = state.reqstate.result; + + DEBUGASSERT(state.valuelen <= arglen); + DEBUGASSERT(state.valuelen <= state.valuelen_nontrunc); + } + + usrsock_teardown_datain(conn); + usrsock_teardown_data_request_callback(&state); + +errout_unlock: + net_unlock(); + + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_listen.c b/net/usrsock/usrsock_listen.c new file mode 100644 index 0000000000..546055438d --- /dev/null +++ b/net/usrsock/usrsock_listen.c @@ -0,0 +1,241 @@ +/**************************************************************************** + * net/usrsock/usrsock_listen.c + * + * Copyright (C) 2018 Pinecone Inc. All rights reserved. + * Author: Xiang Xiao + * + * 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. Neither the name NuttX 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK) + +#include +#include +#include + +#include +#include +#include + +#include "usrsock/usrsock.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t listen_event(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct usrsock_reqstate_s *pstate = pvpriv; + FAR struct usrsock_conn_s *conn = pvconn; + + if (flags & USRSOCK_EVENT_ABORT) + { + ninfo("socket aborted.\n"); + + pstate->result = -ECONNABORTED; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->recvsem); + } + else if (flags & USRSOCK_EVENT_REQ_COMPLETE) + { + ninfo("request completed.\n"); + + pstate->result = conn->resp.result; + + /* Stop further callbacks */ + + pstate->cb->flags = 0; + pstate->cb->priv = NULL; + pstate->cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->recvsem); + } + + return flags; +} + +/**************************************************************************** + * Name: do_listen_request + ****************************************************************************/ + +static int do_listen_request(FAR struct usrsock_conn_s *conn, int backlog) +{ + struct usrsock_request_listen_s req = {}; + struct iovec bufs[1]; + + if (backlog > UINT16_MAX) + { + backlog = UINT16_MAX; + } + + /* Prepare request for daemon to read. */ + + req.head.reqid = USRSOCK_REQUEST_LISTEN; + req.usockid = conn->usockid; + req.backlog = backlog; + + bufs[0].iov_base = &req; + bufs[0].iov_len = sizeof(req); + + return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usrsock_listen + * + * Description: + * To accept connections, a socket is first created with psock_socket(), a + * willingness to accept incoming connections and a queue limit for + * incoming connections are specified with psock_listen(), and then the + * connections are accepted with psock_accept(). For the case of AFINET + * and AFINET6 sockets, psock_listen() calls this function. The + * psock_listen() call applies only to sockets of type SOCK_STREAM or + * SOCK_SEQPACKET. + * + * Parameters: + * psock Reference to an internal, bound socket structure. + * backlog The maximum length the queue of pending connections may grow. + * If a connection request arrives with the queue full, the client + * may receive an error with an indication of ECONNREFUSED or, + * if the underlying protocol supports retransmission, the request + * may be ignored so that retries succeed. + * + * Returned Value: + * On success, zero is returned. On error, a negated errno value is + * returned. See list() for the set of appropriate error values. + * + ****************************************************************************/ + +int usrsock_listen(FAR struct socket *psock, int backlog) +{ + FAR struct usrsock_conn_s *conn = psock->s_conn; + struct usrsock_reqstate_s state = {}; + int ret; + + DEBUGASSERT(conn); + + net_lock(); + + if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || + conn->state == USRSOCK_CONN_STATE_ABORTED) + { + /* Invalid state or closed by daemon. */ + + ninfo("usockid=%d; listen() with uninitialized usrsock.\n", + conn->usockid); + + ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNREFUSED; + goto errout_unlock; + } + + if (conn->connected) + { + /* Already connected. */ + + ret = -EISCONN; + goto errout_unlock; + } + + if (conn->state == USRSOCK_CONN_STATE_CONNECTING) + { + /* Already connecting. */ + + ninfo("usockid=%d; socket already connecting.\n", + conn->usockid); + + ret = -EALREADY; + goto errout_unlock; + } + + /* Set up event callback for usrsock. */ + + ret = usrsock_setup_request_callback(conn, &state, listen_event, + USRSOCK_EVENT_ABORT | + USRSOCK_EVENT_REQ_COMPLETE); + if (ret < 0) + { + nwarn("usrsock_setup_request_callback failed: %d\n", ret); + + goto errout_unlock; + } + + /* Mark conn as listening(reuse connecting here) one. */ + + conn->state = USRSOCK_CONN_STATE_CONNECTING; + + /* Send request. */ + + ret = do_listen_request(conn, backlog); + if (ret < 0) + { + goto errout_teardown; + } + + /* Wait for completion of request (or signal). */ + + ret = net_lockedwait(&state.recvsem); + if (ret < 0) + { + DEBUGASSERT(ret == -EINTR); + + /* Wait interrupted, exit early. */ + + goto errout_teardown; + } + + ret = state.result; + +errout_teardown: + usrsock_teardown_request_callback(&state); +errout_unlock: + net_unlock(); + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */ diff --git a/net/usrsock/usrsock_sockif.c b/net/usrsock/usrsock_sockif.c index 903163afa9..5f74f52174 100644 --- a/net/usrsock/usrsock_sockif.c +++ b/net/usrsock/usrsock_sockif.c @@ -59,11 +59,6 @@ static int usrsock_sockif_setup(FAR struct socket *psock, int protocol); static sockcaps_t usrsock_sockif_sockcaps(FAR struct socket *psock); static void usrsock_sockif_addref(FAR struct socket *psock); -static int usrsock_sockif_listen(FAR struct socket *psock, int backlog); -static int usrsock_sockif_accept(FAR struct socket *psock, - FAR struct sockaddr *addr, - FAR socklen_t *addrlen, - FAR struct socket *newsock); static ssize_t usrsock_sockif_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags); @@ -80,10 +75,10 @@ const struct sock_intf_s g_usrsock_sockif = usrsock_sockif_addref, /* si_addref */ usrsock_bind, /* si_bind */ usrsock_getsockname, /* si_getsockname */ - NULL, /* si_getpeername */ - usrsock_sockif_listen, /* si_listen */ + usrsock_getpeername, /* si_getpeername */ + usrsock_listen, /* si_listen */ usrsock_connect, /* si_connect */ - usrsock_sockif_accept, /* si_accept */ + usrsock_accept, /* si_accept */ #ifndef CONFIG_DISABLE_POLL usrsock_poll, /* si_poll */ #endif @@ -93,7 +88,8 @@ const struct sock_intf_s g_usrsock_sockif = NULL, /* si_sendfile */ #endif usrsock_recvfrom, /* si_recvfrom */ - usrsock_sockif_close /* si_close */ + usrsock_sockif_close, /* si_close */ + usrsock_ioctl /* si_ioctl */ }; /**************************************************************************** @@ -227,92 +223,6 @@ static void usrsock_sockif_addref(FAR struct socket *psock) conn->crefs++; } -/**************************************************************************** - * Name: usrsock_sockif_listen - * - * Description: - * To accept connections, a socket is first created with psock_socket(), a - * willingness to accept incoming connections and a queue limit for - * incoming connections are specified with psock_listen(), and then the - * connections are accepted with psock_accept(). For the case of AFINET - * and AFINET6 sockets, psock_listen() calls this function. The - * psock_listen() call applies only to sockets of type SOCK_STREAM or - * SOCK_SEQPACKET. - * - * Input Parameters: - * psock Reference to an internal, boound socket structure. - * backlog The maximum length the queue of pending connections may grow. - * If a connection request arrives with the queue full, the client - * may receive an error with an indication of ECONNREFUSED or, - * if the underlying protocol supports retransmission, the request - * may be ignored so that retries succeed. - * - * Returned Value: - * On success, zero is returned. On error, a negated errno value is - * returned. See list() for the set of appropriate error values. - * - ****************************************************************************/ - -int usrsock_sockif_listen(FAR struct socket *psock, int backlog) -{ -#warning "Missing logic for USRSOCK listen" - - return -EOPNOTSUPP; -} - -/**************************************************************************** - * Name: usrsock_sockif_accept - * - * Description: - * The usrsock_sockif_accept function is used with connection-based socket - * types (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first - * connection request on the queue of pending connections, creates a new - * connected socket with mostly the same properties as 'sockfd', and - * allocates a new socket descriptor for the socket, which is returned. The - * newly created socket is no longer in the listening state. The original - * socket 'sockfd' is unaffected by this call. Per file descriptor flags - * are not inherited across an inet_accept. - * - * The 'sockfd' argument is a socket descriptor that has been created with - * socket(), bound to a local address with bind(), and is listening for - * connections after a call to listen(). - * - * On return, the 'addr' structure is filled in with the address of the - * connecting entity. The 'addrlen' argument initially contains the size - * of the structure pointed to by 'addr'; on return it will contain the - * actual length of the address returned. - * - * If no pending connections are present on the queue, and the socket is - * not marked as non-blocking, inet_accept blocks the caller until a - * connection is present. If the socket is marked non-blocking and no - * pending connections are present on the queue, inet_accept returns - * EAGAIN. - * - * Input Parameters: - * psock Reference to the listening socket structure - * addr Receives the address of the connecting client - * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' - * newsock Location to return the accepted socket information. - * - * Returned Value: - * Returns 0 (OK) on success. On failure, it returns a negated errno - * value. See accept() for a desrciption of the approriate error value. - * - * Assumptions: - * The network is locked. - * - ****************************************************************************/ - -static int usrsock_sockif_accept(FAR struct socket *psock, - FAR struct sockaddr *addr, - FAR socklen_t *addrlen, - FAR struct socket *newsock) -{ -#warning "Missing logic for USRSOCK accept" - - return -EOPNOTSUPP; -} - /**************************************************************************** * Name: usrsock_sockif_send *