You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/09/24 15:09:38 UTC
[incubator-nuttx] 04/04: net/local: add socket message control
support
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 1b5d6aa068ec5113ae5b105f8120b865ea89b5a0
Author: chao.an <an...@xiaomi.com>
AuthorDate: Wed Sep 15 23:22:18 2021 +0800
net/local: add socket message control support
Signed-off-by: chao.an <an...@xiaomi.com>
---
net/local/Kconfig | 6 ++
net/local/local.h | 26 ++++++---
net/local/local_accept.c | 3 +
net/local/local_conn.c | 26 +++++++++
net/local/local_connect.c | 3 +
net/local/local_recvmsg.c | 111 ++++++++++++++++++++++++++++++++++--
net/local/local_sendmsg.c | 139 ++++++++++++++++++++++++++++++++++++++++++++--
7 files changed, 296 insertions(+), 18 deletions(-)
diff --git a/net/local/Kconfig b/net/local/Kconfig
index e32c0b3..158282b 100644
--- a/net/local/Kconfig
+++ b/net/local/Kconfig
@@ -33,6 +33,12 @@ config NET_LOCAL_DGRAM
---help---
Enable support for Unix domain SOCK_DGRAM type sockets
+config NET_LOCAL_SCM
+ bool "Unix domain socket control message"
+ default n
+ ---help---
+ Enable support for Unix domain socket control message
+
endif # NET_LOCAL
endmenu # Unix Domain Sockets
diff --git a/net/local/local.h b/net/local/local.h
index c746b51..df0777d 100644
--- a/net/local/local.h
+++ b/net/local/local.h
@@ -46,6 +46,7 @@
****************************************************************************/
#define LOCAL_NPOLLWAITERS 2
+#define LOCAL_NCONTROLFDS 4
/* Packet format in FIFO:
*
@@ -136,15 +137,22 @@ struct local_conn_s
/* Fields common to SOCK_STREAM and SOCK_DGRAM */
- uint8_t lc_crefs; /* Reference counts on this instance */
- uint8_t lc_proto; /* SOCK_STREAM or SOCK_DGRAM */
- uint8_t lc_type; /* See enum local_type_e */
- uint8_t lc_state; /* See enum local_state_e */
- struct file lc_infile; /* File for read-only FIFO (peers) */
- struct file lc_outfile; /* File descriptor of write-only FIFO (peers) */
- char lc_path[UNIX_PATH_MAX]; /* Path assigned by bind() */
- int32_t lc_instance_id; /* Connection instance ID for stream
- * server<->client connection pair */
+ uint8_t lc_crefs; /* Reference counts on this instance */
+ uint8_t lc_proto; /* SOCK_STREAM or SOCK_DGRAM */
+ uint8_t lc_type; /* See enum local_type_e */
+ uint8_t lc_state; /* See enum local_state_e */
+ struct file lc_infile; /* File for read-only FIFO (peers) */
+ struct file lc_outfile; /* File descriptor of write-only FIFO (peers) */
+ char lc_path[UNIX_PATH_MAX]; /* Path assigned by bind() */
+ int32_t lc_instance_id; /* Connection instance ID for stream
+ * server<->client connection pair */
+#ifdef CONFIG_NET_LOCAL_SCM
+ FAR struct local_conn_s *
+ lc_peer; /* Peer connection instance */
+ uint16_t lc_cfpcount; /* Control file pointer counter */
+ FAR struct file *
+ lc_cfps[LOCAL_NCONTROLFDS]; /* Socket message control filep */
+#endif /* CONFIG_NET_LOCAL_SCM */
#ifdef CONFIG_NET_LOCAL_STREAM
/* SOCK_STREAM fields common to both client and server */
diff --git a/net/local/local_accept.c b/net/local/local_accept.c
index 4529dab..8d4bec5 100644
--- a/net/local/local_accept.c
+++ b/net/local/local_accept.c
@@ -168,6 +168,9 @@ int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
conn->lc_type = LOCAL_TYPE_PATHNAME;
conn->lc_state = LOCAL_STATE_CONNECTED;
conn->lc_psock = psock;
+#ifdef CONFIG_NET_LOCAL_SCM
+ conn->lc_peer = client;
+#endif /* CONFIG_NET_LOCAL_SCM */
strncpy(conn->lc_path, client->lc_path, UNIX_PATH_MAX - 1);
conn->lc_path[UNIX_PATH_MAX - 1] = '\0';
diff --git a/net/local/local_conn.c b/net/local/local_conn.c
index 3b27400..c968cca 100644
--- a/net/local/local_conn.c
+++ b/net/local/local_conn.c
@@ -161,12 +161,24 @@ FAR struct local_conn_s *local_alloc(void)
void local_free(FAR struct local_conn_s *conn)
{
+#ifdef CONFIG_NET_LOCAL_SCM
+ int i;
+#endif /* CONFIG_NET_LOCAL_SCM */
+
DEBUGASSERT(conn != NULL);
/* Remove the server from the list of listeners. */
net_lock();
dq_rem(&conn->lc_node, &g_local_connections);
+
+#ifdef CONFIG_NET_LOCAL_SCM
+ if (local_peerconn(conn) && conn->lc_peer)
+ {
+ conn->lc_peer->lc_peer = NULL;
+ }
+#endif /* CONFIG_NET_LOCAL_SCM */
+
net_unlock();
/* Make sure that the read-only FIFO is closed */
@@ -185,6 +197,20 @@ void local_free(FAR struct local_conn_s *conn)
conn->lc_outfile.f_inode = NULL;
}
+#ifdef CONFIG_NET_LOCAL_SCM
+ /* Free the pending control file pointer */
+
+ for (i = 0; i < conn->lc_cfpcount; i++)
+ {
+ if (conn->lc_cfps[i])
+ {
+ file_close(conn->lc_cfps[i]);
+ kmm_free(conn->lc_cfps[i]);
+ conn->lc_cfps[i] = NULL;
+ }
+ }
+#endif /* CONFIG_NET_LOCAL_SCM */
+
#ifdef CONFIG_NET_LOCAL_STREAM
/* Destroy all FIFOs associted with the connection */
diff --git a/net/local/local_connect.c b/net/local/local_connect.c
index b3aff31..1c3f407 100644
--- a/net/local/local_connect.c
+++ b/net/local/local_connect.c
@@ -301,6 +301,9 @@ int psock_local_connect(FAR struct socket *psock,
UNIX_PATH_MAX - 1);
client->lc_path[UNIX_PATH_MAX - 1] = '\0';
client->lc_instance_id = local_generate_instance_id();
+#ifdef CONFIG_NET_LOCAL_SCM
+ client->lc_peer = conn;
+#endif /* CONFIG_NET_LOCAL_SCM */
/* The client is now bound to an address */
diff --git a/net/local/local_recvmsg.c b/net/local/local_recvmsg.c
index 6cc1237..9ef2287 100644
--- a/net/local/local_recvmsg.c
+++ b/net/local/local_recvmsg.c
@@ -33,6 +33,8 @@
#include <assert.h>
#include <debug.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/fs/fs.h>
#include <nuttx/net/net.h>
#include "socket/socket.h"
@@ -106,6 +108,93 @@ static int psock_fifo_read(FAR struct socket *psock, FAR void *buf,
}
/****************************************************************************
+ * Name: local_recvctl
+ *
+ * Description:
+ * Handle the socket message conntrol field
+ *
+ * Input Parameters:
+ * conn Local connection instance
+ * msg Message to send
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_LOCAL_SCM
+static void local_recvctl(FAR struct local_conn_s *conn,
+ FAR struct msghdr *msg)
+{
+ FAR struct local_conn_s *peer;
+ struct cmsghdr *cmsg;
+ int count;
+ int *fds;
+ int i;
+
+ net_lock();
+
+ cmsg = CMSG_FIRSTHDR(msg);
+ count = (cmsg->cmsg_len - sizeof(struct cmsghdr)) / sizeof(int);
+ cmsg->cmsg_len = 0;
+
+ if (count == 0)
+ {
+ goto out;
+ }
+
+ if (conn->lc_peer == NULL)
+ {
+ peer = local_peerconn(conn);
+ if (peer == NULL)
+ {
+ goto out;
+ }
+ }
+ else
+ {
+ peer = conn;
+ }
+
+ if (peer->lc_cfpcount == 0)
+ {
+ goto out;
+ }
+
+ fds = (int *)CMSG_DATA(cmsg);
+
+ count = count > peer->lc_cfpcount ?
+ peer->lc_cfpcount : count;
+ for (i = 0; i < count; i++)
+ {
+ fds[i] = file_dup(peer->lc_cfps[i], 0);
+ file_close(peer->lc_cfps[i]);
+ kmm_free(peer->lc_cfps[i]);
+ peer->lc_cfps[i] = NULL;
+ peer->lc_cfpcount--;
+ if (fds[i] < 0)
+ {
+ i++;
+ break;
+ }
+ }
+
+ if (i > 0)
+ {
+ if (peer->lc_cfpcount)
+ {
+ memmove(peer->lc_cfps[0], peer->lc_cfps[i],
+ sizeof(FAR void *) * peer->lc_cfpcount);
+ }
+
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int) * i);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ }
+
+out:
+ net_unlock();
+}
+#endif /* CONFIG_NET_LOCAL_SCM */
+
+/****************************************************************************
* Name: psock_stream_recvfrom
*
* Description:
@@ -382,10 +471,10 @@ errout_with_halfduplex:
ssize_t local_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
int flags)
{
+ FAR socklen_t *fromlen = &msg->msg_namelen;
+ FAR struct sockaddr *from = msg->msg_name;
FAR void *buf = msg->msg_iov->iov_base;
size_t len = msg->msg_iov->iov_len;
- FAR struct sockaddr *from = msg->msg_name;
- FAR socklen_t *fromlen = &msg->msg_namelen;
DEBUGASSERT(psock && psock->s_conn && buf);
@@ -394,7 +483,7 @@ ssize_t local_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
#ifdef CONFIG_NET_LOCAL_STREAM
if (psock->s_type == SOCK_STREAM)
{
- return psock_stream_recvfrom(psock, buf, len, flags, from, fromlen);
+ len = psock_stream_recvfrom(psock, buf, len, flags, from, fromlen);
}
else
#endif
@@ -402,15 +491,27 @@ ssize_t local_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
#ifdef CONFIG_NET_LOCAL_DGRAM
if (psock->s_type == SOCK_DGRAM)
{
- return psock_dgram_recvfrom(psock, buf, len, flags, from, fromlen);
+ len = psock_dgram_recvfrom(psock, buf, len, flags, from, fromlen);
}
else
#endif
{
DEBUGPANIC();
nerr("ERROR: Unrecognized socket type: %" PRIu8 "\n", psock->s_type);
- return -EINVAL;
+ len = -EINVAL;
+ }
+
+#ifdef CONFIG_NET_LOCAL_SCM
+ /* Receive the control message */
+
+ if (len >= 0 && msg->msg_control &&
+ msg->msg_controllen > sizeof(struct cmsghdr))
+ {
+ local_recvctl(psock->s_conn, msg);
}
+#endif /* CONFIG_NET_LOCAL_SCM */
+
+ return len;
}
#endif /* CONFIG_NET && CONFIG_NET_LOCAL */
diff --git a/net/local/local_sendmsg.c b/net/local/local_sendmsg.c
index dd50f40..31c2114 100644
--- a/net/local/local_sendmsg.c
+++ b/net/local/local_sendmsg.c
@@ -32,6 +32,7 @@
#include <assert.h>
#include <debug.h>
+#include <nuttx/kmalloc.h>
#include <nuttx/net/net.h>
#include "socket/socket.h"
@@ -42,6 +43,105 @@
****************************************************************************/
/****************************************************************************
+ * Name: local_sendctl
+ *
+ * Description:
+ * Handle the socket message conntrol field
+ *
+ * Input Parameters:
+ * conn Local connection instance
+ * msg Message to send
+ *
+ * Returned Value:
+ * On any failure, a negated errno value is returned
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_LOCAL_SCM
+static int local_sendctl(FAR struct local_conn_s *conn,
+ FAR struct msghdr *msg)
+{
+ FAR struct local_conn_s *peer;
+ FAR struct file *filep2;
+ FAR struct file *filep;
+ struct cmsghdr *cmsg;
+ int count;
+ int *fds;
+ int ret;
+ int i;
+
+ net_lock();
+
+ peer = conn->lc_peer;
+ if (peer == NULL)
+ {
+ peer = conn;
+ }
+
+ for_each_cmsghdr(cmsg, msg)
+ {
+ if (!CMSG_OK(msg, cmsg) ||
+ cmsg->cmsg_level != SOL_SOCKET ||
+ cmsg->cmsg_type != SCM_RIGHTS)
+ {
+ ret = -EOPNOTSUPP;
+ goto fail;
+ }
+
+ fds = (int *)CMSG_DATA(cmsg);
+ count = (cmsg->cmsg_len - sizeof(struct cmsghdr)) / sizeof(int);
+
+ if (count + peer->lc_cfpcount > LOCAL_NCONTROLFDS)
+ {
+ ret = -EMFILE;
+ goto fail;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ ret = fs_getfilep(fds[i], &filep);
+ if (ret < 0)
+ {
+ goto fail;
+ }
+
+ filep2 = (FAR struct file *)kmm_zalloc(sizeof(*filep2));
+ if (!filep2)
+ {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ ret = file_dup2(filep, filep2);
+ if (ret < 0)
+ {
+ kmm_free(filep2);
+ goto fail;
+ }
+
+ peer->lc_cfps[peer->lc_cfpcount++] = filep2;
+ }
+ }
+
+ net_unlock();
+
+ return count;
+
+fail:
+ while (i-- > 0)
+ {
+ file_close(peer->lc_cfps[--peer->lc_cfpcount]);
+ kmm_free(peer->lc_cfps[peer->lc_cfpcount]);
+ peer->lc_cfps[peer->lc_cfpcount] = NULL;
+ }
+
+ net_unlock();
+
+ return ret;
+}
+#endif /* CONFIG_NET_LOCAL_SCM */
+
+/****************************************************************************
* Name: local_send
*
* Description:
@@ -284,13 +384,44 @@ errout_with_halfduplex:
ssize_t local_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
int flags)
{
- FAR const struct iovec *buf = msg->msg_iov;
- size_t len = msg->msg_iovlen;
FAR const struct sockaddr *to = msg->msg_name;
+ FAR const struct iovec *buf = msg->msg_iov;
socklen_t tolen = msg->msg_namelen;
+ size_t len = msg->msg_iovlen;
+#ifdef CONFIG_NET_LOCAL_SCM
+ FAR struct local_conn_s *conn = psock->s_conn;
+ int count;
+
+ if (msg->msg_control &&
+ msg->msg_controllen > sizeof(struct cmsghdr))
+ {
+ count = local_sendctl(conn, msg);
+ if (count < 0)
+ {
+ return count;
+ }
+ }
+#endif /* CONFIG_NET_LOCAL_SCM */
+
+ len = to ? local_sendto(psock, buf, len, flags, to, tolen) :
+ local_send(psock, buf, len, flags);
+#ifdef CONFIG_NET_LOCAL_SCM
+ if (len < 0 && count > 0)
+ {
+ net_lock();
+
+ while (count-- > 0)
+ {
+ file_close(conn->lc_cfps[--conn->lc_cfpcount]);
+ kmm_free(conn->lc_cfps[conn->lc_cfpcount]);
+ conn->lc_cfps[conn->lc_cfpcount] = NULL;
+ }
+
+ net_unlock();
+ }
+#endif
- return to ? local_sendto(psock, buf, len, flags, to, tolen) :
- local_send(psock, buf, len, flags);
+ return len;
}
#endif /* CONFIG_NET && CONFIG_NET_LOCAL */