usrsock:refine usrsock's architecture

Seperate usrsock device driver with usrsock core function layer
to make it more flexiable to adopt other kind of usrsock interface driver

Signed-off-by: liangchaozhong <liangchaozhong@xiaomi.com>
This commit is contained in:
liangchaozhong 2022-09-01 10:11:44 +08:00 committed by Masayuki Ishikawa
parent d10cd8d585
commit 644c4afeed
20 changed files with 847 additions and 683 deletions

View file

@ -37,6 +37,10 @@
* Pre-processor Definitions
****************************************************************************/
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
/* Event message flags */
#define USRSOCK_EVENT_ABORT (1 << 1)
@ -255,4 +259,48 @@ begin_packed_struct struct usrsock_message_socket_event_s
int16_t usockid;
} end_packed_struct;
/****************************************************************************
* Name: usrsock_iovec_get() - copy from iovec to buffer.
****************************************************************************/
ssize_t usrsock_iovec_get(FAR void *dst, size_t dstlen,
FAR const struct iovec *iov, int iovcnt,
size_t pos);
/****************************************************************************
* Name: usrsock_iovec_put() - copy to iovec from buffer.
****************************************************************************/
ssize_t usrsock_iovec_put(FAR struct iovec *iov, int iovcnt, size_t pos,
FAR const void *src, size_t srclen);
/****************************************************************************
* Name: usrsock_abort() - abort all usrsock's operations
****************************************************************************/
void usrsock_abort(void);
/****************************************************************************
* Name: usrsock_response() - handle usrsock request's ack/response
****************************************************************************/
ssize_t usrsock_response(FAR const char *buffer, size_t len,
FAR bool *req_done);
/****************************************************************************
* Name: usrsock_request() - finish usrsock's request
****************************************************************************/
int usrsock_request(FAR struct iovec *iov, unsigned int iovcnt);
/****************************************************************************
* Name: usrsock_register
*
* Description:
* Register /dev/usrsock
*
****************************************************************************/
void usrsock_register(void);
#endif /* __INCLUDE_NUTTX_NET_USRSOCK_H */

View file

@ -23,7 +23,7 @@
ifeq ($(CONFIG_NET_USRSOCK),y)
NET_CSRCS += usrsock_close.c usrsock_conn.c usrsock_bind.c usrsock_connect.c
NET_CSRCS += usrsock_dev.c usrsock_getpeername.c
NET_CSRCS += usrsock_dev.c usrsock_getpeername.c usrsock_devif.c
NET_CSRCS += usrsock_event.c usrsock_getsockname.c usrsock_getsockopt.c
NET_CSRCS += usrsock_poll.c usrsock_recvmsg.c usrsock_sendmsg.c
NET_CSRCS += usrsock_setsockopt.c usrsock_socket.c usrsock_sockif.c

View file

@ -42,10 +42,6 @@
* Pre-processor Definitions
****************************************************************************/
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
/* Internal socket type/domain for marking usrsock sockets */
#define SOCK_USRSOCK_TYPE 0x7f
@ -62,8 +58,6 @@
* Public Type Definitions
****************************************************************************/
struct usrsockdev_s;
enum usrsock_conn_state_e
{
USRSOCK_CONN_STATE_UNINITIALIZED = 0,
@ -103,6 +97,7 @@ struct usrsock_conn_s
uint16_t valuelen; /* Length of value from daemon */
uint16_t valuelen_nontrunc; /* Actual length of value at daemon */
int result; /* Result for request */
uint16_t events; /* Response events for the request */
struct
{
@ -265,24 +260,19 @@ void usrsock_setup_datain(FAR struct usrsock_conn_s *conn,
*
****************************************************************************/
int usrsock_event(FAR struct usrsock_conn_s *conn, uint16_t events);
int usrsock_event(FAR struct usrsock_conn_s *conn);
/****************************************************************************
* Name: usrsockdev_do_request
****************************************************************************/
int usrsockdev_do_request(FAR struct usrsock_conn_s *conn,
FAR struct iovec *iov, unsigned int iovcnt);
/****************************************************************************
* Name: usrsockdev_register
* Name: usrsock_do_request
*
* Description:
* Register /dev/usrsock
* The usrsock_do_request() function will send usrsock request message
* to the usrsock network interface driver
*
****************************************************************************/
void usrsockdev_register(void);
int usrsock_do_request(FAR struct usrsock_conn_s *conn,
FAR struct iovec *iov, unsigned int iovcnt);
/****************************************************************************
* Name: usrsock_socket

View file

@ -161,7 +161,7 @@ static int do_accept_request(FAR struct usrsock_conn_s *conn,
bufs[0].iov_base = &req;
bufs[0].iov_len = sizeof(req);
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -110,7 +110,7 @@ static int do_bind_request(FAR struct usrsock_conn_s *conn,
bufs[1].iov_base = (FAR void *)addr;
bufs[1].iov_len = req.addrlen;
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -106,7 +106,7 @@ static int do_close_request(FAR struct usrsock_conn_s *conn)
bufs[0].iov_base = (FAR void *)&req;
bufs[0].iov_len = sizeof(req);
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -37,6 +37,7 @@
#include <nuttx/semaphore.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/net.h>
#include <nuttx/net/usrsock.h>
#include "usrsock/usrsock.h"
@ -348,7 +349,7 @@ void usrsock_initialize(void)
/* Register /dev/usrsock character device. */
usrsockdev_register();
usrsock_register();
}
#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */

View file

@ -98,6 +98,7 @@ static int do_connect_request(FAR struct usrsock_conn_s *conn,
};
struct iovec bufs[2];
int ret;
if (addrlen > UINT16_MAX)
{
@ -115,7 +116,13 @@ static int do_connect_request(FAR struct usrsock_conn_s *conn,
bufs[1].iov_base = (FAR void *)addr;
bufs[1].iov_len = addrlen;
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
ret = usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
if (ret == -ENETDOWN)
{
ret = -ECONNABORTED;
}
return ret;
}
/****************************************************************************

View file

@ -44,9 +44,6 @@
#include <nuttx/net/net.h>
#include <nuttx/net/usrsock.h>
#include "devif/devif.h"
#include "usrsock/usrsock.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -63,23 +60,12 @@ struct usrsockdev_s
{
sem_t devsem; /* Lock for device node */
uint8_t ocount; /* The number of times the device has been opened */
uint32_t newxid; /* New transcation Id */
struct
{
FAR const struct iovec *iov; /* Pending request buffers */
int iovcnt; /* Number of request buffers */
size_t pos; /* Reader position on request buffer */
sem_t sem; /* Request semaphore (only one outstanding
* request) */
sem_t acksem; /* Request acknowledgment notification */
uint32_t ackxid; /* Exchange id for which waiting ack */
uint16_t nbusy; /* Number of requests blocked from different
* threads */
} req;
FAR struct usrsock_conn_s *datain_conn; /* Connection instance to receive
* data buffers. */
struct pollfd *pollfds[CONFIG_NET_USRSOCKDEV_NPOLLWAITERS];
};
@ -129,123 +115,6 @@ static struct usrsockdev_s g_usrsockdev;
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: iovec_do() - copy to/from iovec from/to buffer.
****************************************************************************/
static ssize_t iovec_do(FAR void *srcdst, size_t srcdstlen,
FAR struct iovec *iov, int iovcnt, size_t pos,
bool from_iov)
{
ssize_t total;
size_t srclen;
FAR uint8_t *ioout = srcdst;
FAR uint8_t *iovbuf;
/* Rewind to correct position. */
while (pos >= 0 && iovcnt > 0)
{
if (iov->iov_len <= pos)
{
pos -= iov->iov_len;
iov++;
iovcnt--;
}
else
{
break;
}
}
if (iovcnt == 0)
{
/* Position beyond iovec. */
return -1;
}
iovbuf = iov->iov_base;
srclen = iov->iov_len;
iovbuf += pos;
srclen -= pos;
iov++;
iovcnt--;
total = 0;
while ((srclen > 0 || iovcnt > 0) && srcdstlen > 0)
{
size_t clen = srclen;
if (srclen == 0)
{
/* Skip empty iovec. */
iovbuf = iov->iov_base;
srclen = iov->iov_len;
iov++;
iovcnt--;
continue;
}
if (clen > srcdstlen)
{
clen = srcdstlen;
}
if (from_iov)
{
memmove(ioout, iovbuf, clen);
}
else
{
memmove(iovbuf, ioout, clen);
}
ioout += clen;
srcdstlen -= clen;
iovbuf += clen;
srclen -= clen;
total += clen;
if (srclen == 0)
{
if (iovcnt == 0)
{
break;
}
iovbuf = iov->iov_base;
srclen = iov->iov_len;
iov++;
iovcnt--;
}
}
return total;
}
/****************************************************************************
* Name: iovec_get() - copy from iovec to buffer.
****************************************************************************/
static ssize_t iovec_get(FAR void *dst, size_t dstlen,
FAR const struct iovec *iov, int iovcnt, size_t pos)
{
return iovec_do(dst, dstlen, (FAR struct iovec *)iov, iovcnt, pos, true);
}
/****************************************************************************
* Name: iovec_put() - copy to iovec from buffer.
****************************************************************************/
static ssize_t iovec_put(FAR struct iovec *iov, int iovcnt, size_t pos,
FAR const void *src, size_t srclen)
{
return iovec_do((FAR void *)src, srclen, iov, iovcnt, pos, false);
}
/****************************************************************************
* Name: usrsockdev_semtake() and usrsockdev_semgive()
*
@ -336,8 +205,6 @@ static ssize_t usrsockdev_read(FAR struct file *filep, FAR char *buffer,
return ret;
}
net_lock();
/* Is request available? */
if (dev->req.iov)
@ -346,8 +213,8 @@ static ssize_t usrsockdev_read(FAR struct file *filep, FAR char *buffer,
/* Copy request to user-space. */
rlen = iovec_get(buffer, len, dev->req.iov, dev->req.iovcnt,
dev->req.pos);
rlen = usrsock_iovec_get(buffer, len, dev->req.iov, dev->req.iovcnt,
dev->req.pos);
if (rlen < 0)
{
/* Tried reading beyond buffer. */
@ -365,7 +232,6 @@ static ssize_t usrsockdev_read(FAR struct file *filep, FAR char *buffer,
len = 0;
}
net_unlock();
usrsockdev_semgive(&dev->devsem);
return len;
@ -400,8 +266,6 @@ static off_t usrsockdev_seek(FAR struct file *filep, off_t offset,
return ret;
}
net_lock();
/* Is request available? */
if (dev->req.iov)
@ -419,7 +283,8 @@ static off_t usrsockdev_seek(FAR struct file *filep, off_t offset,
/* Copy request to user-space. */
rlen = iovec_get(NULL, 0, dev->req.iov, dev->req.iovcnt, pos);
rlen = usrsock_iovec_get(NULL, 0, dev->req.iov, dev->req.iovcnt,
pos);
if (rlen < 0)
{
/* Tried seek beyond buffer. */
@ -436,352 +301,11 @@ static off_t usrsockdev_seek(FAR struct file *filep, off_t offset,
pos = 0;
}
net_unlock();
usrsockdev_semgive(&dev->devsem);
return pos;
}
/****************************************************************************
* Name: usrsockdev_handle_event
****************************************************************************/
static ssize_t usrsockdev_handle_event(FAR struct usrsockdev_s *dev,
FAR const void *buffer,
size_t len)
{
FAR const struct usrsock_message_common_s *common = buffer;
switch (common->msgid)
{
case USRSOCK_MESSAGE_SOCKET_EVENT:
{
FAR const struct usrsock_message_socket_event_s *hdr = buffer;
FAR struct usrsock_conn_s *conn;
int ret;
if (len < sizeof(*hdr))
{
nwarn("message too short, %zu < %zu.\n", len, sizeof(*hdr));
return -EINVAL;
}
/* Get corresponding usrsock connection. */
conn = usrsock_active(hdr->usockid);
if (!conn)
{
nwarn("no active connection for usockid=%d.\n", hdr->usockid);
return -ENOENT;
}
#ifdef CONFIG_DEV_RANDOM
/* Add randomness. */
add_sw_randomness((hdr->head.events << 16) - hdr->usockid);
#endif
/* Handle event. */
ret = usrsock_event(conn,
hdr->head.events & ~USRSOCK_EVENT_INTERNAL_MASK);
if (ret < 0)
{
return ret;
}
len = sizeof(*hdr);
}
break;
default:
nwarn("Unknown event type: %d\n", common->msgid);
return -EINVAL;
}
return len;
}
/****************************************************************************
* Name: usrsockdev_handle_response
****************************************************************************/
static ssize_t usrsockdev_handle_response(FAR struct usrsockdev_s *dev,
FAR struct usrsock_conn_s *conn,
FAR const void *buffer)
{
FAR const struct usrsock_message_req_ack_s *hdr = buffer;
if (USRSOCK_MESSAGE_REQ_IN_PROGRESS(hdr->head.flags))
{
/* In-progress response is acknowledgment that response was
* received.
*/
conn->resp.inprogress = true;
}
else
{
conn->resp.inprogress = false;
conn->resp.xid = 0;
/* Get result for common request. */
conn->resp.result = hdr->result;
/* Done with request/response. */
usrsock_event(conn, USRSOCK_EVENT_REQ_COMPLETE);
}
return sizeof(*hdr);
}
/****************************************************************************
* Name: usrsockdev_handle_datareq_response
****************************************************************************/
static ssize_t
usrsockdev_handle_datareq_response(FAR struct usrsockdev_s *dev,
FAR struct usrsock_conn_s *conn,
FAR const void *buffer)
{
FAR const struct usrsock_message_datareq_ack_s *datahdr = buffer;
FAR const struct usrsock_message_req_ack_s *hdr = &datahdr->reqack;
int num_inbufs;
int iovpos;
ssize_t ret;
if (USRSOCK_MESSAGE_REQ_IN_PROGRESS(hdr->head.flags))
{
if (datahdr->reqack.result > 0)
{
ninfo("error: request in progress, and result > 0.\n");
ret = -EINVAL;
goto unlock_out;
}
else if (datahdr->valuelen > 0)
{
ninfo("error: request in progress, and valuelen > 0.\n");
ret = -EINVAL;
goto unlock_out;
}
/* In-progress response is acknowledgment that response was
* received.
*/
conn->resp.inprogress = true;
ret = sizeof(*datahdr);
goto unlock_out;
}
conn->resp.inprogress = false;
conn->resp.xid = 0;
/* Prepare to read buffers. */
conn->resp.result = hdr->result;
conn->resp.valuelen = datahdr->valuelen;
conn->resp.valuelen_nontrunc = datahdr->valuelen_nontrunc;
if (conn->resp.result < 0)
{
/* Error, valuelen must be zero. */
if (datahdr->valuelen > 0 || datahdr->valuelen_nontrunc > 0)
{
nerr("error: response result negative, and valuelen or "
"valuelen_nontrunc non-zero.\n");
ret = -EINVAL;
goto unlock_out;
}
/* Done with request/response. */
usrsock_event(conn, USRSOCK_EVENT_REQ_COMPLETE);
ret = sizeof(*datahdr);
goto unlock_out;
}
/* Check that number of buffers match available. */
num_inbufs = (hdr->result > 0) + 1;
if (conn->resp.datain.iovcnt < num_inbufs)
{
nwarn("not enough recv buffers (need: %d, have: %d).\n", num_inbufs,
conn->resp.datain.iovcnt);
ret = -EINVAL;
goto unlock_out;
}
/* Adjust length of receiving buffers. */
conn->resp.datain.total = 0;
iovpos = 0;
/* Value buffer is always the first */
if (conn->resp.datain.iov[iovpos].iov_len < datahdr->valuelen)
{
nwarn("%dth buffer not large enough (need: %d, have: %zu).\n",
iovpos,
datahdr->valuelen,
conn->resp.datain.iov[iovpos].iov_len);
ret = -EINVAL;
goto unlock_out;
}
/* Adjust read size. */
conn->resp.datain.iov[iovpos].iov_len = datahdr->valuelen;
conn->resp.datain.total += conn->resp.datain.iov[iovpos].iov_len;
iovpos++;
if (hdr->result > 0)
{
/* Value buffer is always the first */
if (conn->resp.datain.iov[iovpos].iov_len < hdr->result)
{
nwarn("%dth buffer not large enough "
"(need: %" PRId32 ", have: %zu).\n",
iovpos,
hdr->result,
conn->resp.datain.iov[iovpos].iov_len);
ret = -EINVAL;
goto unlock_out;
}
/* Adjust read size. */
conn->resp.datain.iov[iovpos].iov_len = hdr->result;
conn->resp.datain.total += conn->resp.datain.iov[iovpos].iov_len;
iovpos++;
}
DEBUGASSERT(num_inbufs == iovpos);
conn->resp.datain.iovcnt = num_inbufs;
/* Next written buffers are redirected to data buffers. */
dev->datain_conn = conn;
ret = sizeof(*datahdr);
unlock_out:
return ret;
}
/****************************************************************************
* Name: usrsockdev_handle_req_response
****************************************************************************/
static ssize_t usrsockdev_handle_req_response(FAR struct usrsockdev_s *dev,
FAR const void *buffer,
size_t len)
{
FAR const struct usrsock_message_req_ack_s *hdr = buffer;
FAR struct usrsock_conn_s *conn = NULL;
unsigned int hdrlen;
ssize_t ret;
ssize_t (*handle_response)(FAR struct usrsockdev_s *dev,
FAR struct usrsock_conn_s *conn,
FAR const void *buffer);
switch (hdr->head.msgid)
{
case USRSOCK_MESSAGE_RESPONSE_ACK:
hdrlen = sizeof(struct usrsock_message_req_ack_s);
handle_response = &usrsockdev_handle_response;
break;
case USRSOCK_MESSAGE_RESPONSE_DATA_ACK:
hdrlen = sizeof(struct usrsock_message_datareq_ack_s);
handle_response = &usrsockdev_handle_datareq_response;
break;
default:
nwarn("unknown message type: %d, flags: %d, xid: %" PRIu32 ", "
"result: %" PRId32 "\n",
hdr->head.msgid, hdr->head.flags, hdr->xid, hdr->result);
return -EINVAL;
}
if (len < hdrlen)
{
nwarn("message too short, %zu < %u.\n", len, hdrlen);
return -EINVAL;
}
net_lock();
/* Get corresponding usrsock connection for this transfer */
while ((conn = usrsock_nextconn(conn)) != NULL &&
conn->resp.xid != hdr->xid);
if (!conn)
{
/* No connection waiting for this message. */
nwarn("Could find connection waiting for response"
"with xid=%" PRIu32 "\n", hdr->xid);
ret = -EINVAL;
goto unlock_out;
}
if (dev->req.ackxid == hdr->xid && dev->req.iov)
{
/* Signal that request was received and read by daemon and
* acknowledgment response was received.
*/
dev->req.iov = NULL;
nxsem_post(&dev->req.acksem);
}
ret = handle_response(dev, conn, buffer);
unlock_out:
net_unlock();
return ret;
}
/****************************************************************************
* Name: usrsockdev_handle_message
****************************************************************************/
static ssize_t usrsockdev_handle_message(FAR struct usrsockdev_s *dev,
FAR const void *buffer,
size_t len)
{
FAR const struct usrsock_message_common_s *common = buffer;
if (USRSOCK_MESSAGE_IS_EVENT(common->flags))
{
return usrsockdev_handle_event(dev, buffer, len);
}
if (USRSOCK_MESSAGE_IS_REQ_RESPONSE(common->flags))
{
return usrsockdev_handle_req_response(dev, buffer, len);
}
return -EINVAL;
}
/****************************************************************************
* Name: usrsockdev_write
****************************************************************************/
@ -790,10 +314,9 @@ static ssize_t usrsockdev_write(FAR struct file *filep,
FAR const char *buffer, size_t len)
{
FAR struct inode *inode = filep->f_inode;
FAR struct usrsock_conn_s *conn;
FAR struct usrsockdev_s *dev;
size_t origlen = len;
ssize_t ret = 0;
bool req_done = false;
if (len == 0)
{
@ -817,73 +340,14 @@ static ssize_t usrsockdev_write(FAR struct file *filep,
return ret;
}
if (!dev->datain_conn)
ret = usrsock_response(buffer, len, &req_done);
if (req_done && dev->req.iov)
{
/* Start of message, buffer length should be at least size of common
* message header.
*/
if (len < sizeof(struct usrsock_message_common_s))
{
nwarn("message too short, %zu < %zu.\n", len,
sizeof(struct usrsock_message_common_s));
ret = -EINVAL;
goto errout;
}
/* Handle message. */
ret = usrsockdev_handle_message(dev, buffer, len);
if (ret >= 0)
{
buffer += ret;
len -= ret;
ret = origlen - len;
}
dev->req.iov = NULL;
dev->req.pos = 0;
dev->req.iovcnt = 0;
}
/* Data input handling. */
if (dev->datain_conn)
{
conn = dev->datain_conn;
/* Copy data from user-space. */
if (len != 0)
{
ret = iovec_put(conn->resp.datain.iov, conn->resp.datain.iovcnt,
conn->resp.datain.pos, buffer, len);
if (ret < 0)
{
/* Tried writing beyond buffer. */
ret = -EINVAL;
conn->resp.result = -EINVAL;
conn->resp.datain.pos =
conn->resp.datain.total;
}
else
{
conn->resp.datain.pos += ret;
buffer += ret;
len -= ret;
ret = origlen - len;
}
}
if (conn->resp.datain.pos == conn->resp.datain.total)
{
dev->datain_conn = NULL;
/* Done with data response. */
usrsock_event(conn, USRSOCK_EVENT_REQ_COMPLETE);
}
}
errout:
usrsockdev_semgive(&dev->devsem);
return ret;
}
@ -942,7 +406,6 @@ static int usrsockdev_open(FAR struct file *filep)
static int usrsockdev_close(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct usrsock_conn_s *conn = NULL;
FAR struct usrsockdev_s *dev;
int ret;
@ -960,65 +423,17 @@ static int usrsockdev_close(FAR struct file *filep)
ninfo("closing /dev/usrsock\n");
net_lock();
/* Set active usrsock sockets to aborted state. */
while ((conn = usrsock_nextconn(conn)) != NULL)
{
conn->resp.inprogress = false;
conn->resp.xid = 0;
usrsock_event(conn, USRSOCK_EVENT_ABORT);
}
/* Decrement the references to the driver. */
dev->ocount--;
DEBUGASSERT(dev->ocount == 0);
ret = OK;
do
{
/* Give other threads short time window to complete recently completed
* requests.
*/
ret = net_timedwait(&dev->req.sem, 10);
if (ret < 0)
{
if (ret != -ETIMEDOUT && ret != -EINTR)
{
ninfo("net_timedwait errno: %d\n", ret);
DEBUGPANIC();
}
}
else
{
usrsockdev_semgive(&dev->req.sem);
}
/* Wake-up pending requests. */
if (dev->req.nbusy == 0)
{
break;
}
dev->req.iov = NULL;
nxsem_post(&dev->req.acksem);
}
while (true);
net_unlock();
/* Check if request line is active */
if (dev->req.iov != NULL)
{
dev->req.iov = NULL;
}
dev->req.iov = NULL;
dev->req.iovcnt = 0;
dev->req.pos = 0;
usrsockdev_semgive(&dev->devsem);
usrsock_abort();
return ret;
}
@ -1057,7 +472,6 @@ static int usrsockdev_poll(FAR struct file *filep, FAR struct pollfd *fds,
return ret;
}
net_lock();
if (setup)
{
/* This is a request to set up the poll. Find an available
@ -1092,8 +506,8 @@ static int usrsockdev_poll(FAR struct file *filep, FAR struct pollfd *fds,
/* Notify the POLLIN event if pending request. */
if (dev->req.iov != NULL &&
!(iovec_get(NULL, 0, dev->req.iov,
dev->req.iovcnt, dev->req.pos) < 0))
!(usrsock_iovec_get(NULL, 0, dev->req.iov,
dev->req.iovcnt, dev->req.pos) < 0))
{
eventset |= POLLIN;
}
@ -1122,7 +536,6 @@ static int usrsockdev_poll(FAR struct file *filep, FAR struct pollfd *fds,
}
errout:
net_unlock();
usrsockdev_semgive(&dev->devsem);
return ret;
}
@ -1132,46 +545,21 @@ errout:
****************************************************************************/
/****************************************************************************
* Name: usrsockdev_do_request
* Name: usrsock_request
****************************************************************************/
int usrsockdev_do_request(FAR struct usrsock_conn_s *conn,
FAR struct iovec *iov, unsigned int iovcnt)
int usrsock_request(FAR struct iovec *iov, unsigned int iovcnt)
{
FAR struct usrsockdev_s *dev = &g_usrsockdev;
FAR struct usrsock_request_common_s *req_head = iov[0].iov_base;
if (!usrsockdev_is_opened(dev))
{
ninfo("usockid=%d; daemon has closed /dev/usrsock.\n", conn->usockid);
return -ENETDOWN;
}
/* Get exchange id. */
if (++dev->newxid == 0)
{
++dev->newxid;
}
req_head->xid = dev->newxid;
/* Prepare connection for response. */
conn->resp.xid = req_head->xid;
conn->resp.result = -EACCES;
++dev->req.nbusy; /* net_lock held. */
int ret = 0;
/* Set outstanding request for daemon to handle. */
net_lockedwait_uninterruptible(&dev->req.sem);
net_lockedwait_uninterruptible(&dev->devsem);
if (usrsockdev_is_opened(dev))
{
DEBUGASSERT(dev->req.iov == NULL);
dev->req.ackxid = req_head->xid;
dev->req.iov = iov;
dev->req.pos = 0;
dev->req.iovcnt = iovcnt;
@ -1179,44 +567,32 @@ int usrsockdev_do_request(FAR struct usrsock_conn_s *conn,
/* Notify daemon of new request. */
usrsockdev_pollnotify(dev, POLLIN);
/* Wait ack for request. */
net_lockedwait_uninterruptible(&dev->req.acksem);
}
else
{
ninfo("usockid=%d; daemon abruptly closed /dev/usrsock.\n",
conn->usockid);
ninfo("daemon abruptly closed /dev/usrsock.\n");
ret = -ENETDOWN;
}
/* Free request line for next command. */
usrsockdev_semgive(&dev->devsem);
usrsockdev_semgive(&dev->req.sem);
--dev->req.nbusy; /* net_lock held. */
return OK;
return ret;
}
/****************************************************************************
* Name: usrsockdev_register
* Name: usrsock_register
*
* Description:
* Register /dev/usrsock
*
****************************************************************************/
void usrsockdev_register(void)
void usrsock_register(void)
{
/* Initialize device private structure. */
g_usrsockdev.ocount = 0;
g_usrsockdev.req.nbusy = 0;
nxsem_init(&g_usrsockdev.devsem, 0, 1);
nxsem_init(&g_usrsockdev.req.sem, 0, 1);
nxsem_init(&g_usrsockdev.req.acksem, 0, 0);
nxsem_set_protocol(&g_usrsockdev.req.acksem, SEM_PRIO_NONE);
register_driver("/dev/usrsock", &g_usrsockdevops, 0666,
&g_usrsockdev);

740
net/usrsock/usrsock_devif.c Normal file
View file

@ -0,0 +1,740 @@
/****************************************************************************
* net/usrsock/usrsock_devif.c
*
* 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>
#if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK)
#include <sys/types.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/random.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include <nuttx/net/usrsock.h>
#include "usrsock/usrsock.h"
/****************************************************************************
* Private Types
****************************************************************************/
struct usrsock_req_s
{
sem_t sem; /* Request semaphore (only one outstanding
* request) */
sem_t acksem; /* Request acknowledgment notification */
uint32_t newxid; /* New transcation Id */
uint32_t ackxid; /* Exchange id for which waiting ack */
uint16_t nbusy; /* Number of requests blocked from different
* threads */
/* Connection instance to receive data buffers. */
FAR struct usrsock_conn_s *datain_conn;
};
/****************************************************************************
* Private Data
****************************************************************************/
/* only support 1 usrsock network interface for the moment,
* define it into array or construct a list
* if multiple usrsock network interfaces are needed in the future
*/
static struct usrsock_req_s g_usrsock_req =
{
NXSEM_INITIALIZER(1, PRIOINHERIT_FLAGS_DISABLE),
NXSEM_INITIALIZER(0, PRIOINHERIT_FLAGS_DISABLE),
0,
0,
0,
NULL
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: usrsock_iovec_do() - copy to/from iovec from/to buffer.
****************************************************************************/
static ssize_t usrsock_iovec_do(FAR void *srcdst, size_t srcdstlen,
FAR struct iovec *iov, int iovcnt,
size_t pos, bool from_iov)
{
ssize_t total = 0;
size_t srclen = 0;
FAR uint8_t *ioout = srcdst;
FAR uint8_t *iovbuf;
/* Rewind to correct position. */
while (pos >= 0 && iovcnt > 0)
{
if (iov->iov_len <= pos)
{
pos -= iov->iov_len;
iov++;
iovcnt--;
}
else
{
break;
}
}
if (iovcnt == 0)
{
/* Position beyond iovec. */
total = -EINVAL;
goto out;
}
iovbuf = iov->iov_base;
srclen = iov->iov_len;
iovbuf += pos;
srclen -= pos;
iov++;
iovcnt--;
while ((srclen > 0 || iovcnt > 0) && srcdstlen > 0)
{
size_t clen = srclen;
if (srclen == 0)
{
/* Skip empty iovec. */
iovbuf = iov->iov_base;
srclen = iov->iov_len;
iov++;
iovcnt--;
continue;
}
if (clen > srcdstlen)
{
clen = srcdstlen;
}
if (from_iov)
{
memmove(ioout, iovbuf, clen);
}
else
{
memmove(iovbuf, ioout, clen);
}
ioout += clen;
srcdstlen -= clen;
iovbuf += clen;
srclen -= clen;
total += clen;
if (srclen == 0)
{
if (iovcnt == 0)
{
break;
}
iovbuf = iov->iov_base;
srclen = iov->iov_len;
iov++;
iovcnt--;
}
}
out:
return total;
}
/****************************************************************************
* Name: usrsock_handle_event
****************************************************************************/
static ssize_t usrsock_handle_event(FAR const void *buffer, size_t len)
{
FAR const struct usrsock_message_common_s *common = buffer;
switch (common->msgid)
{
case USRSOCK_MESSAGE_SOCKET_EVENT:
{
FAR const struct usrsock_message_socket_event_s *hdr = buffer;
FAR struct usrsock_conn_s *conn;
int ret;
if (len < sizeof(*hdr))
{
nwarn("message too short, %zu < %zu.\n", len, sizeof(*hdr));
return -EINVAL;
}
/* Get corresponding usrsock connection. */
conn = usrsock_active(hdr->usockid);
if (!conn)
{
nwarn("no active connection for usockid=%d.\n", hdr->usockid);
return -ENOENT;
}
#ifdef CONFIG_DEV_RANDOM
/* Add randomness. */
add_sw_randomness((hdr->head.events << 16) - hdr->usockid);
#endif
/* Handle event. */
conn->resp.events = hdr->head.events & ~USRSOCK_EVENT_INTERNAL_MASK;
ret = usrsock_event(conn);
if (ret < 0)
{
return ret;
}
len = sizeof(*hdr);
}
break;
default:
nwarn("Unknown event type: %d\n", common->msgid);
return -EINVAL;
}
return len;
}
/****************************************************************************
* Name: usrsock_handle_response
****************************************************************************/
static ssize_t usrsock_handle_response(FAR struct usrsock_conn_s *conn,
FAR const void *buffer,
size_t len)
{
FAR const struct usrsock_message_req_ack_s *hdr = buffer;
if (USRSOCK_MESSAGE_REQ_IN_PROGRESS(hdr->head.flags))
{
/* In-progress response is acknowledgment that response was
* received.
*/
conn->resp.inprogress = true;
}
else
{
conn->resp.inprogress = false;
conn->resp.xid = 0;
/* Get result for common request. */
conn->resp.result = hdr->result;
/* Done with request/response. */
usrsock_event(conn);
}
return sizeof(*hdr);
}
/****************************************************************************
* Name: usrsock_handle_datareq_response
****************************************************************************/
static ssize_t
usrsock_handle_datareq_response(FAR struct usrsock_conn_s *conn,
FAR const void *buffer,
size_t len)
{
FAR const struct usrsock_message_datareq_ack_s *datahdr = buffer;
FAR const struct usrsock_message_req_ack_s *hdr = &datahdr->reqack;
FAR struct usrsock_req_s *req = &g_usrsock_req;
int num_inbufs;
int iovpos;
ssize_t ret;
if (USRSOCK_MESSAGE_REQ_IN_PROGRESS(hdr->head.flags))
{
if (datahdr->reqack.result > 0)
{
ninfo("error: request in progress, and result > 0.\n");
ret = -EINVAL;
goto unlock_out;
}
else if (datahdr->valuelen > 0)
{
ninfo("error: request in progress, and valuelen > 0.\n");
ret = -EINVAL;
goto unlock_out;
}
/* In-progress response is acknowledgment that response was
* received.
*/
conn->resp.inprogress = true;
ret = sizeof(*datahdr);
goto unlock_out;
}
conn->resp.inprogress = false;
conn->resp.xid = 0;
/* Prepare to read buffers. */
conn->resp.result = hdr->result;
conn->resp.valuelen = datahdr->valuelen;
conn->resp.valuelen_nontrunc = datahdr->valuelen_nontrunc;
if (conn->resp.result < 0)
{
/* Error, valuelen must be zero. */
if (datahdr->valuelen > 0 || datahdr->valuelen_nontrunc > 0)
{
nerr("error: response result negative, and valuelen or "
"valuelen_nontrunc non-zero.\n");
ret = -EINVAL;
goto unlock_out;
}
/* Done with request/response. */
usrsock_event(conn);
ret = sizeof(*datahdr);
goto unlock_out;
}
/* Check that number of buffers match available. */
num_inbufs = (hdr->result > 0) + 1;
if (conn->resp.datain.iovcnt < num_inbufs)
{
nwarn("not enough recv buffers (need: %d, have: %d).\n", num_inbufs,
conn->resp.datain.iovcnt);
ret = -EINVAL;
goto unlock_out;
}
/* Adjust length of receiving buffers. */
conn->resp.datain.total = 0;
iovpos = 0;
/* Value buffer is always the first */
if (conn->resp.datain.iov[iovpos].iov_len < datahdr->valuelen)
{
nwarn("%dth buffer not large enough (need: %d, have: %zu).\n",
iovpos,
datahdr->valuelen,
conn->resp.datain.iov[iovpos].iov_len);
ret = -EINVAL;
goto unlock_out;
}
/* Adjust read size. */
conn->resp.datain.iov[iovpos].iov_len = datahdr->valuelen;
conn->resp.datain.total += conn->resp.datain.iov[iovpos].iov_len;
iovpos++;
if (hdr->result > 0)
{
/* Value buffer is always the first */
if (conn->resp.datain.iov[iovpos].iov_len < hdr->result)
{
nwarn("%dth buffer not large enough "
"(need: %" PRId32 ", have: %zu).\n",
iovpos,
hdr->result,
conn->resp.datain.iov[iovpos].iov_len);
ret = -EINVAL;
goto unlock_out;
}
/* Adjust read size. */
conn->resp.datain.iov[iovpos].iov_len = hdr->result;
conn->resp.datain.total += conn->resp.datain.iov[iovpos].iov_len;
iovpos++;
}
DEBUGASSERT(num_inbufs == iovpos);
conn->resp.datain.iovcnt = num_inbufs;
/* Next written buffers are redirected to data buffers. */
req->datain_conn = conn;
ret = sizeof(*datahdr);
unlock_out:
return ret;
}
/****************************************************************************
* Name: usrsock_handle_req_response
****************************************************************************/
static ssize_t usrsock_handle_req_response(FAR const void *buffer,
size_t len, FAR bool *req_done)
{
FAR const struct usrsock_message_req_ack_s *hdr = buffer;
FAR struct usrsock_conn_s *conn = NULL;
FAR struct usrsock_req_s *req = &g_usrsock_req;
ssize_t (*handle_response)(FAR struct usrsock_conn_s *conn,
FAR const void *buffer,
size_t len);
size_t hdrlen;
ssize_t ret;
switch (hdr->head.msgid)
{
case USRSOCK_MESSAGE_RESPONSE_ACK:
hdrlen = sizeof(struct usrsock_message_req_ack_s);
handle_response = &usrsock_handle_response;
break;
case USRSOCK_MESSAGE_RESPONSE_DATA_ACK:
hdrlen = sizeof(struct usrsock_message_datareq_ack_s);
handle_response = &usrsock_handle_datareq_response;
break;
default:
nwarn("unknown message type: %d, flags: %d, xid: %" PRIu32 ", "
"result: %" PRId32 "\n",
hdr->head.msgid, hdr->head.flags, hdr->xid, hdr->result);
return -EINVAL;
}
if (len < hdrlen)
{
nwarn("message too short, %zu < %zu.\n", len, hdrlen);
return -EINVAL;
}
net_lock();
/* Get corresponding usrsock connection for this transfer */
while ((conn = usrsock_nextconn(conn)) != NULL &&
conn->resp.xid != hdr->xid);
if (!conn)
{
/* No connection waiting for this message. */
nwarn("Could find connection waiting for response"
"with xid=%" PRIu32 "\n", hdr->xid);
ret = -EINVAL;
goto unlock_out;
}
if (req->ackxid == hdr->xid)
{
req->ackxid = 0;
if (req_done)
{
*req_done = true;
}
/* Signal that request was received and read by daemon and
* acknowledgment response was received.
*/
nxsem_post(&req->acksem);
}
conn->resp.events = hdr->head.events | USRSOCK_EVENT_REQ_COMPLETE;
ret = handle_response(conn, buffer, len);
unlock_out:
net_unlock();
return ret;
}
/****************************************************************************
* Name: usrsock_handle_message
****************************************************************************/
static ssize_t usrsock_handle_message(FAR const void *buffer, size_t len,
FAR bool *req_done)
{
FAR const struct usrsock_message_common_s *common = buffer;
if (USRSOCK_MESSAGE_IS_EVENT(common->flags))
{
return usrsock_handle_event(buffer, len);
}
if (USRSOCK_MESSAGE_IS_REQ_RESPONSE(common->flags))
{
return usrsock_handle_req_response(buffer, len, req_done);
}
return -EINVAL;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: usrsock_response() - handle usrsock request's ack/response
****************************************************************************/
ssize_t usrsock_response(FAR const char *buffer, size_t len,
FAR bool *req_done)
{
FAR struct usrsock_req_s *req = &g_usrsock_req;
FAR struct usrsock_conn_s *conn;
size_t origlen = len;
int ret = 0;
if (!req->datain_conn)
{
/* Start of message, buffer length should be at least size of common
* message header.
*/
if (len < sizeof(struct usrsock_message_common_s))
{
nwarn("message too short, %zu < %zu.\n", len,
sizeof(struct usrsock_message_common_s));
ret = -EINVAL;
goto errout;
}
/* Handle message. */
ret = usrsock_handle_message(buffer, len, req_done);
if (ret >= 0)
{
buffer += ret;
len -= ret;
ret = origlen - len;
}
}
if (req->datain_conn)
{
conn = req->datain_conn;
/* Copy data from user-space. */
if (len != 0)
{
ret = usrsock_iovec_put(conn->resp.datain.iov,
conn->resp.datain.iovcnt,
conn->resp.datain.pos, buffer, len);
if (ret < 0)
{
/* Tried writing beyond buffer. */
conn->resp.result = ret;
conn->resp.datain.pos = conn->resp.datain.total;
}
else
{
conn->resp.datain.pos += ret;
buffer += ret;
len -= ret;
ret = origlen - len;
}
}
if (conn->resp.datain.pos == conn->resp.datain.total)
{
req->datain_conn = NULL;
/* Done with data response. */
usrsock_event(conn);
}
}
errout:
return ret;
}
/****************************************************************************
* Name: usrsock_iovec_get() - copy from iovec to buffer.
****************************************************************************/
ssize_t usrsock_iovec_get(FAR void *dst, size_t dstlen,
FAR const struct iovec *iov, int iovcnt,
size_t pos)
{
return usrsock_iovec_do(dst, dstlen, (FAR struct iovec *)iov, iovcnt,
pos, true);
}
/****************************************************************************
* Name: usrsock_iovec_put() - copy to iovec from buffer.
****************************************************************************/
ssize_t usrsock_iovec_put(FAR struct iovec *iov, int iovcnt, size_t pos,
FAR const void *src, size_t srclen)
{
return usrsock_iovec_do((FAR void *)src, srclen, iov, iovcnt,
pos, false);
}
/****************************************************************************
* Name: usrsock_request() - finish usrsock's request
****************************************************************************/
int usrsock_do_request(FAR struct usrsock_conn_s *conn,
FAR struct iovec *iov, unsigned int iovcnt)
{
FAR struct usrsock_request_common_s *req_head = NULL;
FAR struct usrsock_req_s *req = &g_usrsock_req;
int ret;
/* Get exchange id. */
req_head = iov[0].iov_base;
/* Set outstanding request for daemon to handle. */
net_lockedwait_uninterruptible(&req->sem);
if (++req->newxid == 0)
{
++req->newxid;
}
req_head->xid = req->newxid;
/* Prepare connection for response. */
conn->resp.xid = req_head->xid;
conn->resp.result = -EACCES;
req->ackxid = req_head->xid;
ret = usrsock_request(iov, iovcnt);
if (ret == OK)
{
/* Wait ack for request. */
++req->nbusy; /* net_lock held. */
net_lockedwait_uninterruptible(&req->acksem);
--req->nbusy; /* net_lock held. */
}
/* Free request line for next command. */
nxsem_post(&req->sem);
return ret;
}
/****************************************************************************
* Name: usrsock_abort() - abort all usrsock's operations
****************************************************************************/
void usrsock_abort(void)
{
FAR struct usrsock_conn_s *conn = NULL;
FAR struct usrsock_req_s *req = &g_usrsock_req;
int ret;
net_lock();
/* Set active usrsock sockets to aborted state. */
while ((conn = usrsock_nextconn(conn)) != NULL)
{
conn->resp.inprogress = false;
conn->resp.xid = 0;
conn->resp.events = USRSOCK_EVENT_ABORT;
usrsock_event(conn);
}
do
{
/* Give other threads short time window to complete recently completed
* requests.
*/
ret = net_timedwait(&req->sem, 10);
if (ret < 0)
{
if (ret != -ETIMEDOUT && ret != -EINTR)
{
ninfo("net_timedwait errno: %d\n", ret);
DEBUGASSERT(false);
}
}
else
{
nxsem_post(&req->sem);
}
/* Wake-up pending requests. */
if (req->nbusy == 0)
{
break;
}
nxsem_post(&req->acksem);
}
while (true);
net_unlock();
}
#endif /* CONFIG_NET && CONFIG_NET_USRSOCK */

View file

@ -52,8 +52,10 @@
*
****************************************************************************/
int usrsock_event(FAR struct usrsock_conn_s *conn, uint16_t events)
int usrsock_event(FAR struct usrsock_conn_s *conn)
{
uint16_t events = conn->resp.events;
ninfo("events: %04X\n", events);
if (!events)

View file

@ -123,7 +123,7 @@ static int do_getpeername_request(FAR struct usrsock_conn_s *conn,
bufs[0].iov_base = (FAR void *)&req;
bufs[0].iov_len = sizeof(req);
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -123,7 +123,7 @@ static int do_getsockname_request(FAR struct usrsock_conn_s *conn,
bufs[0].iov_base = (FAR void *)&req;
bufs[0].iov_len = sizeof(req);
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -134,7 +134,7 @@ static int do_getsockopt_request(FAR struct usrsock_conn_s *conn, int level,
bufs[0].iov_base = (FAR void *)&req;
bufs[0].iov_len = sizeof(req);
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -139,7 +139,7 @@ static int do_ioctl_request(FAR struct usrsock_conn_s *conn, int cmd,
}
#endif
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -106,7 +106,7 @@ static int do_listen_request(FAR struct usrsock_conn_s *conn, int backlog)
bufs[0].iov_base = &req;
bufs[0].iov_len = sizeof(req);
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -174,7 +174,7 @@ static int do_recvfrom_request(FAR struct usrsock_conn_s *conn,
bufs[0].iov_base = (FAR void *)&req;
bufs[0].iov_len = sizeof(req);
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -171,7 +171,7 @@ static int do_sendto_request(FAR struct usrsock_conn_s *conn,
memcpy(&bufs[2], msg->msg_iov, sizeof(struct iovec) * msg->msg_iovlen);
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -128,7 +128,7 @@ static int do_setsockopt_request(FAR struct usrsock_conn_s *conn,
bufs[1].iov_base = (FAR void *)value;
bufs[1].iov_len = req.valuelen;
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************

View file

@ -133,7 +133,7 @@ static int do_socket_request(FAR struct usrsock_conn_s *conn, int domain,
bufs[0].iov_base = (FAR void *)&req;
bufs[0].iov_len = sizeof(req);
return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
return usrsock_do_request(conn, bufs, ARRAY_SIZE(bufs));
}
/****************************************************************************