mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
net/pkt: add poll function for pkt socket
add poll function for pkt socket Signed-off-by: gaohedong <gaohedong@xiaomi.com>
This commit is contained in:
parent
9e0852c6a4
commit
09e12a58d3
6 changed files with 422 additions and 2 deletions
|
|
@ -34,5 +34,6 @@ if(CONFIG_NET_PKT)
|
|||
pkt_input.c
|
||||
pkt_callback.c
|
||||
pkt_poll.c
|
||||
pkt_netpoll.c
|
||||
pkt_finddev.c)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -61,5 +61,9 @@ config NET_PKT_MAX_CONNS
|
|||
This is useful in case the system is under very heavy load (or
|
||||
under attack), ensuring that the heap will not be exhausted.
|
||||
|
||||
config NET_PKT_NPOLLWAITERS
|
||||
int "Number of PKT poll waiters"
|
||||
default 2
|
||||
|
||||
endif # NET_PKT
|
||||
endmenu # Raw Socket Support
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ NET_CSRCS += pkt_conn.c
|
|||
NET_CSRCS += pkt_input.c
|
||||
NET_CSRCS += pkt_callback.c
|
||||
NET_CSRCS += pkt_poll.c
|
||||
NET_CSRCS += pkt_netpoll.c
|
||||
NET_CSRCS += pkt_finddev.c
|
||||
|
||||
# Include packet socket build support
|
||||
|
|
|
|||
|
|
@ -53,6 +53,16 @@
|
|||
/* Representation of a packet socket connection */
|
||||
|
||||
struct devif_callback_s; /* Forward reference */
|
||||
struct pollfd; /* Forward reference */
|
||||
|
||||
/* This is a container that holds the poll-related information */
|
||||
|
||||
struct pkt_poll_s
|
||||
{
|
||||
FAR struct pkt_conn_s *conn; /* Needed to handle loss of connection */
|
||||
FAR struct pollfd *fds; /* Needed to handle poll events */
|
||||
FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
|
||||
};
|
||||
|
||||
struct pkt_conn_s
|
||||
{
|
||||
|
|
@ -76,6 +86,12 @@ struct pkt_conn_s
|
|||
struct iob_queue_s readahead; /* Read-ahead buffering */
|
||||
|
||||
FAR struct iob_s *pendiob; /* The iob currently being sent */
|
||||
|
||||
/* The following is a list of poll structures of threads waiting for
|
||||
* socket events.
|
||||
*/
|
||||
|
||||
struct pkt_poll_s pollinfo[CONFIG_NET_PKT_NPOLLWAITERS];
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -272,6 +288,42 @@ FAR struct net_driver_s *pkt_find_device(FAR struct pkt_conn_s *conn);
|
|||
|
||||
void pkt_poll(FAR struct net_driver_s *dev, FAR struct pkt_conn_s *conn);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_pollsetup
|
||||
*
|
||||
* Description:
|
||||
* Setup to monitor events on one PKT socket
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock - The PKT 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 pkt_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_pollteardown
|
||||
*
|
||||
* Description:
|
||||
* Teardown monitoring of events on an PKT socket
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock - The PKT 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 pkt_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_sendmsg
|
||||
*
|
||||
|
|
|
|||
323
net/pkt/pkt_netpoll.c
Normal file
323
net/pkt/pkt_netpoll.c
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
/****************************************************************************
|
||||
* net/pkt/pkt_netpoll.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <poll.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/pkt.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
|
||||
#include "devif/devif.h"
|
||||
#include "netdev/netdev.h"
|
||||
#include "socket/socket.h"
|
||||
#include "pkt/pkt.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_pkt_cansend
|
||||
*
|
||||
* Description:
|
||||
* psock_pkt_cansend() returns a value indicating if a write to the socket
|
||||
* would block. It is still possible that the write may block if another
|
||||
* write occurs first.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn A reference to PKT connection structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK (Always can send).
|
||||
*
|
||||
* Assumptions:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int psock_pkt_cansend(FAR struct pkt_conn_s *conn)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_poll_eventhandler
|
||||
*
|
||||
* Description:
|
||||
* This function is called to perform the actual PKT receive operation via
|
||||
* the device interface layer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev The structure of the network driver that caused the event
|
||||
* pvpriv An instance of struct pkt_poll_s cast to void*
|
||||
* flags Set of events describing why the callback was invoked
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint16_t pkt_poll_eventhandler(FAR struct net_driver_s *dev,
|
||||
FAR void *pvpriv, uint16_t flags)
|
||||
{
|
||||
FAR struct pkt_poll_s *info = pvpriv;
|
||||
|
||||
ninfo("flags: %04x\n", flags);
|
||||
|
||||
DEBUGASSERT(!info || (info->conn && info->fds));
|
||||
|
||||
/* 'priv' might be null in some race conditions (?) */
|
||||
|
||||
if (info)
|
||||
{
|
||||
pollevent_t eventset = 0;
|
||||
|
||||
/* Check for data availability events. */
|
||||
|
||||
if ((flags & PKT_NEWDATA) != 0)
|
||||
{
|
||||
eventset |= POLLIN;
|
||||
}
|
||||
|
||||
/* Check for loss of connection events. */
|
||||
|
||||
if ((flags & NETDEV_DOWN) != 0)
|
||||
{
|
||||
eventset |= (POLLHUP | POLLERR);
|
||||
}
|
||||
|
||||
/* A poll is a sign that we are free to send data. */
|
||||
|
||||
else if (psock_pkt_cansend(info->conn) >= 0)
|
||||
{
|
||||
eventset |= POLLOUT;
|
||||
}
|
||||
|
||||
/* Awaken the caller of poll() is requested event occurred. */
|
||||
|
||||
poll_notify(&info->fds, 1, eventset);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_pollsetup
|
||||
*
|
||||
* Description:
|
||||
* Setup to monitor events on one PKT socket
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock - The PKT 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 pkt_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
|
||||
{
|
||||
FAR struct pkt_conn_s *conn;
|
||||
FAR struct pkt_poll_s *info;
|
||||
FAR struct devif_callback_s *cb;
|
||||
FAR struct net_driver_s *dev;
|
||||
pollevent_t eventset = 0;
|
||||
int ret = OK;
|
||||
|
||||
/* Some of the following must be atomic */
|
||||
|
||||
net_lock();
|
||||
|
||||
conn = psock->s_conn;
|
||||
|
||||
/* Sanity check */
|
||||
|
||||
if (conn == NULL || fds == NULL)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
goto errout_with_lock;
|
||||
}
|
||||
|
||||
/* Find a container to hold the poll information */
|
||||
|
||||
info = conn->pollinfo;
|
||||
while (info->conn != NULL)
|
||||
{
|
||||
if (++info >= &conn->pollinfo[CONFIG_NET_PKT_NPOLLWAITERS])
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
goto errout_with_lock;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the device that will provide the provide the NETDEV_DOWN event. */
|
||||
|
||||
dev = pkt_find_device(conn);
|
||||
|
||||
/* Allocate a PKT callback structure */
|
||||
|
||||
cb = pkt_callback_alloc(dev, conn);
|
||||
if (cb == NULL)
|
||||
{
|
||||
ret = -EBUSY;
|
||||
goto errout_with_lock;
|
||||
}
|
||||
|
||||
/* Initialize the poll info container */
|
||||
|
||||
info->conn = conn;
|
||||
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 = NETDEV_DOWN;
|
||||
cb->priv = info;
|
||||
cb->event = pkt_poll_eventhandler;
|
||||
|
||||
if ((fds->events & POLLOUT) != 0)
|
||||
{
|
||||
cb->flags |= PKT_POLL;
|
||||
}
|
||||
|
||||
if ((fds->events & POLLIN) != 0)
|
||||
{
|
||||
cb->flags |= PKT_NEWDATA;
|
||||
}
|
||||
|
||||
/* Save the reference in the poll info structure as fds private as well
|
||||
* for use during poll teardown as well.
|
||||
*/
|
||||
|
||||
fds->priv = info;
|
||||
|
||||
/* Check for read data availability now */
|
||||
|
||||
if (iob_peek_queue(&conn->readahead) != NULL)
|
||||
{
|
||||
/* Normal data may be read without blocking. */
|
||||
|
||||
eventset |= POLLRDNORM;
|
||||
}
|
||||
|
||||
/* Check for write data availability now */
|
||||
|
||||
if (psock_pkt_cansend(conn) >= 0)
|
||||
{
|
||||
/* Normal data may be sent without blocking (at least one byte). */
|
||||
|
||||
eventset |= POLLWRNORM;
|
||||
}
|
||||
|
||||
/* Check if any requested events are already in effect */
|
||||
|
||||
poll_notify(&fds, 1, eventset);
|
||||
|
||||
errout_with_lock:
|
||||
net_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_pollteardown
|
||||
*
|
||||
* Description:
|
||||
* Teardown monitoring of events on an PKT socket
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock - The PKT 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 pkt_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
|
||||
{
|
||||
FAR struct pkt_conn_s *conn;
|
||||
FAR struct pkt_poll_s *info;
|
||||
FAR struct net_driver_s *dev;
|
||||
|
||||
/* Some of the following must be atomic */
|
||||
|
||||
net_lock();
|
||||
|
||||
conn = psock->s_conn;
|
||||
|
||||
/* Sanity check */
|
||||
|
||||
if (!conn || !fds->priv)
|
||||
{
|
||||
net_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Recover the socket descriptor poll state info from the poll structure */
|
||||
|
||||
info = (FAR struct pkt_poll_s *)fds->priv;
|
||||
DEBUGASSERT(info->fds != NULL && info->cb != NULL);
|
||||
if (info != NULL)
|
||||
{
|
||||
/* Get the device that will provide the NETDEV_DOWN event. */
|
||||
|
||||
dev = pkt_find_device(conn);
|
||||
|
||||
/* Release the callback */
|
||||
|
||||
pkt_callback_free(dev, conn, info->cb);
|
||||
|
||||
/* Release the poll/select data slot */
|
||||
|
||||
fds->priv = NULL;
|
||||
|
||||
/* Then free the poll info container */
|
||||
|
||||
info->conn = NULL;
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
@ -53,7 +53,10 @@ static int pkt_setup(FAR struct socket *psock);
|
|||
static sockcaps_t pkt_sockcaps(FAR struct socket *psock);
|
||||
static void pkt_addref(FAR struct socket *psock);
|
||||
static int pkt_bind(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr, socklen_t addrlen);
|
||||
FAR const struct sockaddr *addr,
|
||||
socklen_t addrlen);
|
||||
static int pkt_netpoll(FAR struct socket *psock,
|
||||
FAR struct pollfd *fds, bool setup);
|
||||
static int pkt_close(FAR struct socket *psock);
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -71,7 +74,7 @@ const struct sock_intf_s g_pkt_sockif =
|
|||
NULL, /* si_listen */
|
||||
NULL, /* si_connect */
|
||||
NULL, /* si_accept */
|
||||
NULL, /* si_poll */
|
||||
pkt_netpoll, /* si_poll */
|
||||
pkt_sendmsg, /* si_sendmsg */
|
||||
pkt_recvmsg, /* si_recvmsg */
|
||||
pkt_close /* si_close */
|
||||
|
|
@ -264,6 +267,42 @@ static int pkt_bind(FAR struct socket *psock,
|
|||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_netpoll
|
||||
*
|
||||
* Description:
|
||||
* The standard poll() operation redirects operations on pkt socket
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock - An instance of the internal socket structure.
|
||||
* fds - The structure describing the events to be monitored, OR NULL if
|
||||
* this is a request to stop monitoring events.
|
||||
* setup - true: Setup up the poll; false: Teardown the poll
|
||||
*
|
||||
* Returned Value:
|
||||
* 0: Success; Negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pkt_netpoll(FAR struct socket *psock, FAR struct pollfd *fds,
|
||||
bool setup)
|
||||
{
|
||||
/* Check if we are setting up or tearing down the poll */
|
||||
|
||||
if (setup)
|
||||
{
|
||||
/* Perform the PKT poll() setup */
|
||||
|
||||
return pkt_pollsetup(psock, fds);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Perform the PKT poll() teardown */
|
||||
|
||||
return pkt_pollteardown(psock, fds);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_close
|
||||
*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue