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:
parent
d10cd8d585
commit
644c4afeed
20 changed files with 847 additions and 683 deletions
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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
740
net/usrsock/usrsock_devif.c
Normal 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 */
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
Loading…
Reference in a new issue