diff --git a/net/local/Make.defs b/net/local/Make.defs index 6b101cd7a7..864af12960 100644 --- a/net/local/Make.defs +++ b/net/local/Make.defs @@ -33,7 +33,7 @@ # ############################################################################ -# UDP source files +# Unix domain socket source files ifeq ($(CONFIG_NET_LOCAL),y) @@ -41,7 +41,11 @@ NET_CSRCS += local_conn.c local_connect.c local_release.c local_bind.c NET_CSRCS += local_listen.c local_accept.c local_fifo.c local_recvfrom.c NET_CSRCS += local_send.c local_sendto.c local_sendpacket.c local_recvutils.c -# Include UDP build support +ifneq ($(CONFIG_DISABLE_POLL),y) +NET_CSRCS += local_netpoll.c +endif + +# Include Unix domain socket build support DEPPATH += --dep-path local VPATH += :local diff --git a/net/local/local.h b/net/local/local.h index 7b5356f371..30f08ca691 100644 --- a/net/local/local.h +++ b/net/local/local.h @@ -53,6 +53,9 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* Not yet any support for poll/select operations on Unix domain sockets */ + +#undef HAVE_LOCAL_POLL /* Packet format in FIFO: * diff --git a/net/local/local_netpoll.c b/net/local/local_netpoll.c new file mode 100644 index 0000000000..d0dec448fe --- /dev/null +++ b/net/local/local_netpoll.c @@ -0,0 +1,95 @@ +/**************************************************************************** + * net/local/local_netpoll.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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_DISABLE_POLL) + +#include "local/local.h" + +#ifdef HAVE_LOCAL_POLL + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: local_pollsetup + * + * Description: + * Setup to monitor events on one Unix domain socket + * + * Input Parameters: + * psock - The Unix domain socket of interest + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +int local_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) +{ +#warning Missing logic + return -ENOSYS; +} + +/**************************************************************************** + * Function: local_pollteardown + * + * Description: + * Teardown monitoring of events on a Unix domain socket + * + * Input Parameters: + * psock - The Unix domain socket of interest + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +int local_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds) +{ +#warning Missing logic + return -ENOSYS; +} + +#endif /* HAVE_LOCAL_POLL */ diff --git a/net/socket/net_poll.c b/net/socket/net_poll.c index d2cacf13a0..8dfa41f94b 100644 --- a/net/socket/net_poll.c +++ b/net/socket/net_poll.c @@ -57,24 +57,24 @@ #include #include "tcp/tcp.h" #include "udp/udp.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Network polling can only be supported on TCP and only if read-ahead buffering - * is enabled (it could be supported on UDP as will if it also had read-ahead - * buffering. +/* Network polling can only be supported if poll support is provided by TCP, + * UDP, or LOCAL sockets. */ -#if !defined(CONFIG_DISABLE_POLL) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \ - defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCP_READAHEAD) -# define HAVE_NETPOLL 1 -#else -# undef HAVE_NETPOLL +#undef HAVE_NET_POLL +#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL) || defined(HAVE_LOCAL_POLL) +# define HAVE_NET_POLL 1 #endif +#ifdef HAVE_NET_POLL + /**************************************************************************** * Private Types ****************************************************************************/ @@ -111,7 +111,7 @@ struct net_poll_s * ****************************************************************************/ -#ifdef HAVE_NETPOLL +#ifdef HAVE_TCP_POLL static uint16_t tcp_poll_interrupt(FAR struct net_driver_s *dev, FAR void *conn, FAR void *pvpriv, uint16_t flags) { @@ -162,70 +162,7 @@ static uint16_t tcp_poll_interrupt(FAR struct net_driver_s *dev, FAR void *conn, return flags; } -#endif /* HAVE_NETPOLL */ - -/**************************************************************************** - * Function: udp_poll_interrupt - * - * Description: - * This function is called from the interrupt level to perform the actual - * UDP receive operation via by the device interface layer. - * - * Parameters: - * dev The structure of the network driver that caused the interrupt - * conn The connection structure associated with the socket - * flags Set of events describing why the callback was invoked - * - * Returned Value: - * None - * - * Assumptions: - * Running at the interrupt level - * - ****************************************************************************/ - -#ifdef HAVE_NETPOLL -static uint16_t udp_poll_interrupt(FAR struct net_driver_s *dev, FAR void *conn, - FAR void *pvpriv, uint16_t flags) -{ - FAR struct net_poll_s *info = (FAR struct net_poll_s *)pvpriv; - - nllvdbg("flags: %04x\n", flags); - - DEBUGASSERT(!info || (info->psock && info->fds)); - - /* 'priv' might be null in some race conditions (?) */ - - if (info) - { - pollevent_t eventset = 0; - - /* Check for data or connection availability events. */ - - if ((flags & (UDP_NEWDATA)) != 0) - { - eventset |= (POLLIN & info->fds->events); - } - - /* A poll is a sign that we are free to send data. */ - - if ((flags & UDP_POLL) != 0) - { - eventset |= (POLLOUT & info->fds->events); - } - - /* Awaken the caller of poll() is requested event occurred. */ - - if (eventset) - { - info->fds->revents |= eventset; - sem_post(info->fds->sem); - } - } - - return flags; -} -#endif /* HAVE_NETPOLL */ +#endif /* HAVE_TCP_POLL */ /**************************************************************************** * Function: tcp_pollsetup @@ -243,7 +180,7 @@ static uint16_t udp_poll_interrupt(FAR struct net_driver_s *dev, FAR void *conn, * ****************************************************************************/ -#ifdef HAVE_NETPOLL +#ifdef HAVE_TCP_POLL static inline int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) { @@ -387,121 +324,7 @@ errout_with_lock: net_unlock(flags); return ret; } - -/**************************************************************************** - * Function: udp_pollsetup - * - * Description: - * Setup to monitor events on one UDP/IP socket - * - * Input Parameters: - * psock - The UDP/IP socket of interest - * fds - The structure describing the events to be monitored, OR NULL if - * this is a request to stop monitoring events. - * - * Returned Value: - * 0: Success; Negated errno on failure - * - ****************************************************************************/ - -static inline int udp_pollsetup(FAR struct socket *psock, - FAR struct pollfd *fds) -{ - FAR struct udp_conn_s *conn = psock->s_conn; - FAR struct net_poll_s *info; - FAR struct devif_callback_s *cb; - net_lock_t flags; - int ret; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!conn || !fds) - { - return -EINVAL; - } -#endif - - /* Allocate a container to hold the poll information */ - - info = (FAR struct net_poll_s *)kmm_malloc(sizeof(struct net_poll_s)); - if (!info) - { - return -ENOMEM; - } - - /* Some of the following must be atomic */ - - flags = net_lock(); - - /* Setup the UDP remote connection */ - - ret = udp_connect(conn, NULL); - if (ret) - { - goto errout_with_lock; - } - - /* Allocate a TCP/IP callback structure */ - - cb = udp_callback_alloc(conn); - if (!cb) - { - ret = -EBUSY; - goto errout_with_lock; - } - - /* Initialize the poll info container */ - - info->psock = psock; - info->fds = fds; - info->cb = cb; - - /* Initialize the callback structure. Save the reference to the info - * structure as callback private data so that it will be available during - * callback processing. - */ - - cb->flags = (0); - cb->priv = (FAR void *)info; - cb->event = udp_poll_interrupt; - - if (info->fds->events & POLLOUT) - cb->flags |= UDP_POLL; - if (info->fds->events & POLLIN) - cb->flags |= UDP_NEWDATA; - - /* Save the reference in the poll info structure as fds private as well - * for use durring poll teardown as well. - */ - - fds->priv = (FAR void *)info; - - /* Check for read data availability now */ - - if (!IOB_QEMPTY(&conn->readahead)) - { - /* Normal data may be read without blocking. */ - - fds->revents |= (POLLRDNORM & fds->events); - } - - /* Check if any requested events are already in effect */ - - if (fds->revents != 0) - { - /* Yes.. then signal the poll logic */ - sem_post(fds->sem); - } - - net_unlock(flags); - return OK; - -errout_with_lock: - kmm_free(info); - net_unlock(flags); - return ret; -} +#endif /* HAVE_TCP_POLL */ /**************************************************************************** * Function: net_pollsetup @@ -522,23 +345,54 @@ errout_with_lock: static inline int net_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) { -#ifdef CONFIG_NET_TCP +#if defined(HAVE_TCP_POLL) || defined(HAVE_LOCAL_POLL) if (psock->s_type == SOCK_STREAM) { - return tcp_pollsetup(psock, fds); - } +#ifdef HAVE_LOCAL_POLL +#ifdef HAVE_TCP_POLL + if (psock->s_domain == PF_LOCAL) #endif + { + return local_pollsetup(psock, fds); + } +#endif /* HAVE_LOCAL_POLL */ -#ifdef CONFIG_NET_UDP +#ifdef HAVE_TCP_POLL +#ifdef HAVE_LOCAL_POLL + else +#endif + { + return tcp_pollsetup(psock, fds); + } +#endif /* HAVE_TCP_POLL */ + } +#endif /* HAVE_TCP_POLL || HAVE_LOCAL_POLL */ + +#if defined(HAVE_UDP_POLL) || defined(HAVE_LOCAL_POLL) if (psock->s_type != SOCK_STREAM) { - return udp_pollsetup(psock, fds); - } +#ifdef HAVE_LOCAL_POLL +#ifdef HAVE_UDP_POLL + if (psock->s_domain == PF_LOCAL) #endif + { + return local_pollsetup(psock, fds); + } +#endif /* HAVE_LOCAL_POLL */ + +#ifdef HAVE_UDP_POLL +#ifdef HAVE_LOCAL_POLL + else +#endif + { + return udp_pollsetup(psock, fds); + } +#endif /* HAVE_UDP_POLL */ + } +#endif /* HAVE_UDP_POLL || HAVE_LOCAL_POLL */ return -ENOSYS; } -#endif /* HAVE_NETPOLL */ /**************************************************************************** * Function: tcp_pollteardown @@ -556,7 +410,7 @@ static inline int net_pollsetup(FAR struct socket *psock, * ****************************************************************************/ -#ifdef HAVE_NETPOLL +#ifdef HAVE_TCP_POLL static inline int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds) { @@ -596,62 +450,7 @@ static inline int tcp_pollteardown(FAR struct socket *psock, return OK; } - -/**************************************************************************** - * Function: udp_pollteardown - * - * Description: - * Teardown monitoring of events on an UDP/IP socket - * - * Input Parameters: - * psock - The TCP/IP socket of interest - * fds - The structure describing the events to be monitored, OR NULL if - * this is a request to stop monitoring events. - * - * Returned Value: - * 0: Success; Negated errno on failure - * - ****************************************************************************/ - -static inline int udp_pollteardown(FAR struct socket *psock, - FAR struct pollfd *fds) -{ - FAR struct udp_conn_s *conn = psock->s_conn; - FAR struct net_poll_s *info; - net_lock_t flags; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!conn || !fds->priv) - { - return -EINVAL; - } -#endif - - /* Recover the socket descriptor poll state info from the poll structure */ - - info = (FAR struct net_poll_s *)fds->priv; - DEBUGASSERT(info && info->fds && info->cb); - if (info) - { - /* Release the callback */ - - flags = net_lock(); - udp_callback_free(conn, info->cb); - net_unlock(flags); - - /* Release the poll/select data slot */ - - info->fds->priv = NULL; - - /* Then free the poll info container */ - - kmm_free(info); - } - - return OK; -} +#endif /* HAVE_TCP_POLL */ /**************************************************************************** * Function: net_pollteardown @@ -672,23 +471,55 @@ static inline int udp_pollteardown(FAR struct socket *psock, static inline int net_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds) { -#ifdef CONFIG_NET_TCP +#if defined(HAVE_TCP_POLL) || defined(HAVE_LOCAL_POLL) if (psock->s_type == SOCK_STREAM) { - return tcp_pollteardown(psock, fds); - } +#ifdef HAVE_LOCAL_POLL +#ifdef HAVE_TCP_POLL + if (psock->s_domain == PF_LOCAL) #endif + { + return local_pollteardown(psock, fds); + } +#endif /* HAVE_LOCAL_POLL */ -#ifdef CONFIG_NET_UDP +#ifdef HAVE_TCP_POLL +#ifdef HAVE_LOCAL_POLL + else +#endif + { + return tcp_pollteardown(psock, fds); + } +#endif /* HAVE_TCP_POLL */ + } +#endif /* HAVE_TCP_POLL || HAVE_LOCAL_POLL */ + +#if defined(HAVE_UDP_POLL) || defined(HAVE_LOCAL_POLL) if (psock->s_type != SOCK_STREAM) { - return udp_pollteardown(psock, fds); - } +#ifdef HAVE_LOCAL_POLL +#ifdef HAVE_UDP_POLL + if (psock->s_domain == PF_LOCAL) #endif + { + return local_pollteardown(psock, fds); + } +#endif /* HAVE_LOCAL_POLL */ + +#ifdef HAVE_UDP_POLL +#ifdef HAVE_LOCAL_POLL + else +#endif + { + return udp_pollteardown(psock, fds); + } +#endif /* HAVE_UDP_POLL */ + } +#endif /* HAVE_UDP_POLL || HAVE_LOCAL_POLL */ return -ENOSYS; } -#endif /* HAVE_NETPOLL */ +#endif /* HAVE_NET_POLL */ /**************************************************************************** * Public Functions @@ -712,9 +543,11 @@ static inline int net_pollteardown(FAR struct socket *psock, * ****************************************************************************/ -#if !defined(CONFIG_DISABLE_POLL) && defined(HAVE_NETPOLL) int psock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup) { +#ifndef HAVE_NET_POLL + return -ENOSYS; +#else int ret; /* Check if we are setting up or tearing down the poll */ @@ -733,8 +566,8 @@ int psock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup) } return ret; +#endif /* HAVE_NET_POLL */ } -#endif /**************************************************************************** * Function: net_poll @@ -754,10 +587,9 @@ int psock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup) * ****************************************************************************/ -#ifndef CONFIG_DISABLE_POLL int net_poll(int sockfd, struct pollfd *fds, bool setup) { -#ifndef HAVE_NETPOLL +#ifndef HAVE_NET_POLL return -ENOSYS; #else FAR struct socket *psock; @@ -775,8 +607,7 @@ int net_poll(int sockfd, struct pollfd *fds, bool setup) /* Then let psock_poll() do the heavy lifting */ return psock_poll(psock, fds, setup); -#endif /* HAVE_NETPOLL */ +#endif /* HAVE_NET_POLL */ } -#endif /* !CONFIG_DISABLE_POLL */ #endif /* CONFIG_NET && !CONFIG_DISABLE_POLL */ diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 0f8146b707..72fc3b96b5 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -53,6 +53,12 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* Conditions for support TCP poll/select operations */ + +#if !defined(CONFIG_DISABLE_POLL) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \ + defined(CONFIG_NET_TCP_READAHEAD) +# define HAVE_TCP_POLL +#endif /* Allocate a new TCP data callback */ diff --git a/net/udp/Make.defs b/net/udp/Make.defs index 9cbe77b3df..4cd7b9a1df 100644 --- a/net/udp/Make.defs +++ b/net/udp/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # net/udp/Make.defs # -# Copyright (C) 2014 Gregory Nutt. All rights reserved. +# Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -41,9 +41,15 @@ ifeq ($(CONFIG_NET_UDP),y) NET_CSRCS += udp_sendto.c -# Tranport layer +ifneq ($(CONFIG_DISABLE_POLL),y) +ifeq ($(CONFIG_NET_UDP_READAHEAD),y) +NET_CSRCS += udp_netpoll.c +endif +endif -NET_CSRCS += udp_conn.c udp_poll.c udp_send.c udp_input.c udp_callback.c +# Transport layer + +NET_CSRCS += udp_conn.c udp_devpoll.c udp_send.c udp_input.c udp_callback.c NET_CSRCS += udp_ipselect.c # Include UDP build support diff --git a/net/udp/udp.h b/net/udp/udp.h index 2f193dea0b..ddd470410e 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -56,6 +56,12 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* Conditions for support UDP poll/select operations */ + +#if !defined(CONFIG_DISABLE_POLL) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \ + defined(CONFIG_NET_UDP_READAHEAD) +# define HAVE_UDP_POLL +#endif /* Allocate a new UDP data callback */ @@ -115,6 +121,7 @@ extern "C" struct sockaddr; /* Forward reference */ struct socket; /* Forward reference */ struct net_driver_s; /* Forward reference */ +struct pollfd; /* Forward reference */ /**************************************************************************** * Name: udp_initialize @@ -371,6 +378,46 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, size_t len, int flags, FAR const struct sockaddr *to, socklen_t tolen); +/**************************************************************************** + * Function: udp_pollsetup + * + * Description: + * Setup to monitor events on one UDP/IP socket + * + * Input Parameters: + * psock - The UDP/IP socket of interest + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +#ifdef HAVE_UDP_POLL +int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds); +#endif + +/**************************************************************************** + * Function: udp_pollteardown + * + * Description: + * Teardown monitoring of events on an UDP/IP socket + * + * Input Parameters: + * psock - The TCP/IP socket of interest + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +#ifdef HAVE_UDP_POLL +int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds); +#endif + #undef EXTERN #ifdef __cplusplus } diff --git a/net/udp/udp_poll.c b/net/udp/udp_devpoll.c similarity index 98% rename from net/udp/udp_poll.c rename to net/udp/udp_devpoll.c index b7112bd9ce..8352b7b266 100644 --- a/net/udp/udp_poll.c +++ b/net/udp/udp_devpoll.c @@ -1,6 +1,6 @@ /**************************************************************************** - * net/udp/udp_poll.c - * Poll for the availability of UDP TX data + * net/udp/udp_devpoll.c + * Network device poll for the availability of UDP TX data * * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. * Author: Gregory Nutt diff --git a/net/udp/udp_netpoll.c b/net/udp/udp_netpoll.c new file mode 100644 index 0000000000..0ab9a5f90e --- /dev/null +++ b/net/udp/udp_netpoll.c @@ -0,0 +1,304 @@ +/**************************************************************************** + * net/udp/udp_netpoll.c + * + * Copyright (C) 2008-2009, 2011-2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include +#include + +#include +#include + +#include +#include "udp/udp.h" + +#ifdef HAVE_UDP_POLL + +/**************************************************************************** + * Private Types + ****************************************************************************/ +/* This is an allocated container that holds the poll-related information */ + +struct udp_poll_s +{ + FAR struct socket *psock; /* Needed to handle loss of connection */ + struct pollfd *fds; /* Needed to handle poll events */ + FAR struct devif_callback_s *cb; /* Needed to teardown the poll */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: udp_poll_interrupt + * + * Description: + * This function is called from the interrupt level to perform the actual + * UDP receive operation via by the device interface layer. + * + * Parameters: + * dev The structure of the network driver that caused the interrupt + * conn The connection structure associated with the socket + * flags Set of events describing why the callback was invoked + * + * Returned Value: + * None + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +static uint16_t udp_poll_interrupt(FAR struct net_driver_s *dev, FAR void *conn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct udp_poll_s *info = (FAR struct udp_poll_s *)pvpriv; + + nllvdbg("flags: %04x\n", flags); + + DEBUGASSERT(!info || (info->psock && info->fds)); + + /* 'priv' might be null in some race conditions (?) */ + + if (info) + { + pollevent_t eventset = 0; + + /* Check for data or connection availability events. */ + + if ((flags & (UDP_NEWDATA)) != 0) + { + eventset |= (POLLIN & info->fds->events); + } + + /* A poll is a sign that we are free to send data. */ + + if ((flags & UDP_POLL) != 0) + { + eventset |= (POLLOUT & info->fds->events); + } + + /* Awaken the caller of poll() is requested event occurred. */ + + if (eventset) + { + info->fds->revents |= eventset; + sem_post(info->fds->sem); + } + } + + return flags; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: udp_pollsetup + * + * Description: + * Setup to monitor events on one UDP/IP socket + * + * Input Parameters: + * psock - The UDP/IP socket of interest + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) +{ + FAR struct udp_conn_s *conn = psock->s_conn; + FAR struct udp_poll_s *info; + FAR struct devif_callback_s *cb; + net_lock_t flags; + int ret; + + /* Sanity check */ + +#ifdef CONFIG_DEBUG + if (!conn || !fds) + { + return -EINVAL; + } +#endif + + /* Allocate a container to hold the poll information */ + + info = (FAR struct udp_poll_s *)kmm_malloc(sizeof(struct udp_poll_s)); + if (!info) + { + return -ENOMEM; + } + + /* Some of the following must be atomic */ + + flags = net_lock(); + + /* Setup the UDP remote connection */ + + ret = udp_connect(conn, NULL); + if (ret) + { + goto errout_with_lock; + } + + /* Allocate a TCP/IP callback structure */ + + cb = udp_callback_alloc(conn); + if (!cb) + { + ret = -EBUSY; + goto errout_with_lock; + } + + /* Initialize the poll info container */ + + info->psock = psock; + info->fds = fds; + info->cb = cb; + + /* Initialize the callback structure. Save the reference to the info + * structure as callback private data so that it will be available during + * callback processing. + */ + + cb->flags = (0); + cb->priv = (FAR void *)info; + cb->event = udp_poll_interrupt; + + if (info->fds->events & POLLOUT) + cb->flags |= UDP_POLL; + if (info->fds->events & POLLIN) + cb->flags |= UDP_NEWDATA; + + /* Save the reference in the poll info structure as fds private as well + * for use durring poll teardown as well. + */ + + fds->priv = (FAR void *)info; + + /* Check for read data availability now */ + + if (!IOB_QEMPTY(&conn->readahead)) + { + /* Normal data may be read without blocking. */ + + fds->revents |= (POLLRDNORM & fds->events); + } + + /* Check if any requested events are already in effect */ + + if (fds->revents != 0) + { + /* Yes.. then signal the poll logic */ + sem_post(fds->sem); + } + + net_unlock(flags); + return OK; + +errout_with_lock: + kmm_free(info); + net_unlock(flags); + return ret; +} + +/**************************************************************************** + * Function: udp_pollteardown + * + * Description: + * Teardown monitoring of events on an UDP/IP socket + * + * Input Parameters: + * psock - The TCP/IP socket of interest + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +int udp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds) +{ + FAR struct udp_conn_s *conn = psock->s_conn; + FAR struct udp_poll_s *info; + net_lock_t flags; + + /* Sanity check */ + +#ifdef CONFIG_DEBUG + if (!conn || !fds->priv) + { + return -EINVAL; + } +#endif + + /* Recover the socket descriptor poll state info from the poll structure */ + + info = (FAR struct udp_poll_s *)fds->priv; + DEBUGASSERT(info && info->fds && info->cb); + if (info) + { + /* Release the callback */ + + flags = net_lock(); + udp_callback_free(conn, info->cb); + net_unlock(flags); + + /* Release the poll/select data slot */ + + info->fds->priv = NULL; + + /* Then free the poll info container */ + + kmm_free(info); + } + + return OK; +} + +#endif /* !HAVE_UDP_POLL */