net/local: add socket message control support
Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
parent
ea82a0b638
commit
1b5d6aa068
@ -33,6 +33,12 @@ config NET_LOCAL_DGRAM
|
|||||||
---help---
|
---help---
|
||||||
Enable support for Unix domain SOCK_DGRAM type sockets
|
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
|
endif # NET_LOCAL
|
||||||
|
|
||||||
endmenu # Unix Domain Sockets
|
endmenu # Unix Domain Sockets
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#define LOCAL_NPOLLWAITERS 2
|
#define LOCAL_NPOLLWAITERS 2
|
||||||
|
#define LOCAL_NCONTROLFDS 4
|
||||||
|
|
||||||
/* Packet format in FIFO:
|
/* Packet format in FIFO:
|
||||||
*
|
*
|
||||||
@ -136,15 +137,22 @@ struct local_conn_s
|
|||||||
|
|
||||||
/* Fields common to SOCK_STREAM and SOCK_DGRAM */
|
/* Fields common to SOCK_STREAM and SOCK_DGRAM */
|
||||||
|
|
||||||
uint8_t lc_crefs; /* Reference counts on this instance */
|
uint8_t lc_crefs; /* Reference counts on this instance */
|
||||||
uint8_t lc_proto; /* SOCK_STREAM or SOCK_DGRAM */
|
uint8_t lc_proto; /* SOCK_STREAM or SOCK_DGRAM */
|
||||||
uint8_t lc_type; /* See enum local_type_e */
|
uint8_t lc_type; /* See enum local_type_e */
|
||||||
uint8_t lc_state; /* See enum local_state_e */
|
uint8_t lc_state; /* See enum local_state_e */
|
||||||
struct file lc_infile; /* File for read-only FIFO (peers) */
|
struct file lc_infile; /* File for read-only FIFO (peers) */
|
||||||
struct file lc_outfile; /* File descriptor of write-only FIFO (peers) */
|
struct file lc_outfile; /* File descriptor of write-only FIFO (peers) */
|
||||||
char lc_path[UNIX_PATH_MAX]; /* Path assigned by bind() */
|
char lc_path[UNIX_PATH_MAX]; /* Path assigned by bind() */
|
||||||
int32_t lc_instance_id; /* Connection instance ID for stream
|
int32_t lc_instance_id; /* Connection instance ID for stream
|
||||||
* server<->client connection pair */
|
* 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
|
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||||
/* SOCK_STREAM fields common to both client and server */
|
/* SOCK_STREAM fields common to both client and server */
|
||||||
|
@ -168,6 +168,9 @@ int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
|||||||
conn->lc_type = LOCAL_TYPE_PATHNAME;
|
conn->lc_type = LOCAL_TYPE_PATHNAME;
|
||||||
conn->lc_state = LOCAL_STATE_CONNECTED;
|
conn->lc_state = LOCAL_STATE_CONNECTED;
|
||||||
conn->lc_psock = psock;
|
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);
|
strncpy(conn->lc_path, client->lc_path, UNIX_PATH_MAX - 1);
|
||||||
conn->lc_path[UNIX_PATH_MAX - 1] = '\0';
|
conn->lc_path[UNIX_PATH_MAX - 1] = '\0';
|
||||||
|
@ -161,12 +161,24 @@ FAR struct local_conn_s *local_alloc(void)
|
|||||||
|
|
||||||
void local_free(FAR struct local_conn_s *conn)
|
void local_free(FAR struct local_conn_s *conn)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_NET_LOCAL_SCM
|
||||||
|
int i;
|
||||||
|
#endif /* CONFIG_NET_LOCAL_SCM */
|
||||||
|
|
||||||
DEBUGASSERT(conn != NULL);
|
DEBUGASSERT(conn != NULL);
|
||||||
|
|
||||||
/* Remove the server from the list of listeners. */
|
/* Remove the server from the list of listeners. */
|
||||||
|
|
||||||
net_lock();
|
net_lock();
|
||||||
dq_rem(&conn->lc_node, &g_local_connections);
|
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();
|
net_unlock();
|
||||||
|
|
||||||
/* Make sure that the read-only FIFO is closed */
|
/* 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;
|
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
|
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||||
/* Destroy all FIFOs associted with the connection */
|
/* Destroy all FIFOs associted with the connection */
|
||||||
|
|
||||||
|
@ -301,6 +301,9 @@ int psock_local_connect(FAR struct socket *psock,
|
|||||||
UNIX_PATH_MAX - 1);
|
UNIX_PATH_MAX - 1);
|
||||||
client->lc_path[UNIX_PATH_MAX - 1] = '\0';
|
client->lc_path[UNIX_PATH_MAX - 1] = '\0';
|
||||||
client->lc_instance_id = local_generate_instance_id();
|
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 */
|
/* The client is now bound to an address */
|
||||||
|
|
||||||
|
@ -33,6 +33,8 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/kmalloc.h>
|
||||||
|
#include <nuttx/fs/fs.h>
|
||||||
#include <nuttx/net/net.h>
|
#include <nuttx/net/net.h>
|
||||||
|
|
||||||
#include "socket/socket.h"
|
#include "socket/socket.h"
|
||||||
@ -105,6 +107,93 @@ static int psock_fifo_read(FAR struct socket *psock, FAR void *buf,
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* 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
|
* Name: psock_stream_recvfrom
|
||||||
*
|
*
|
||||||
@ -382,10 +471,10 @@ errout_with_halfduplex:
|
|||||||
ssize_t local_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
ssize_t local_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
|
FAR socklen_t *fromlen = &msg->msg_namelen;
|
||||||
|
FAR struct sockaddr *from = msg->msg_name;
|
||||||
FAR void *buf = msg->msg_iov->iov_base;
|
FAR void *buf = msg->msg_iov->iov_base;
|
||||||
size_t len = msg->msg_iov->iov_len;
|
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);
|
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
|
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||||
if (psock->s_type == SOCK_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
|
else
|
||||||
#endif
|
#endif
|
||||||
@ -402,15 +491,27 @@ ssize_t local_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
|||||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||||
if (psock->s_type == SOCK_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
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
DEBUGPANIC();
|
DEBUGPANIC();
|
||||||
nerr("ERROR: Unrecognized socket type: %" PRIu8 "\n", psock->s_type);
|
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 */
|
#endif /* CONFIG_NET && CONFIG_NET_LOCAL */
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/kmalloc.h>
|
||||||
#include <nuttx/net/net.h>
|
#include <nuttx/net/net.h>
|
||||||
|
|
||||||
#include "socket/socket.h"
|
#include "socket/socket.h"
|
||||||
@ -41,6 +42,105 @@
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* 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
|
* Name: local_send
|
||||||
*
|
*
|
||||||
@ -284,13 +384,44 @@ errout_with_halfduplex:
|
|||||||
ssize_t local_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
ssize_t local_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||||
int flags)
|
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 sockaddr *to = msg->msg_name;
|
||||||
|
FAR const struct iovec *buf = msg->msg_iov;
|
||||||
socklen_t tolen = msg->msg_namelen;
|
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;
|
||||||
|
|
||||||
return to ? local_sendto(psock, buf, len, flags, to, tolen) :
|
if (msg->msg_control &&
|
||||||
local_send(psock, buf, len, flags);
|
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 len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_NET && CONFIG_NET_LOCAL */
|
#endif /* CONFIG_NET && CONFIG_NET_LOCAL */
|
||||||
|
Loading…
Reference in New Issue
Block a user