local_socket: add SO_SNDBUF & SO_RCVBUF support for accept socket

SO_SNDBUF takes effect only after the connection in STREAM mode
is successful
support full life cycle modification of SO_RCVBUF

Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu
2024-08-26 14:48:55 +08:00
committed by Xiang Xiao
parent 98c6cd45db
commit cd86499e83
8 changed files with 160 additions and 77 deletions
+10 -3
View File
@@ -49,6 +49,14 @@
#define LOCAL_NPOLLWAITERS 2 #define LOCAL_NPOLLWAITERS 2
#define LOCAL_NCONTROLFDS 4 #define LOCAL_NCONTROLFDS 4
#if CONFIG_DEV_PIPE_MAXSIZE > 65535
typedef uint32_t lc_size_t; /* 32-bit index */
#elif CONFIG_DEV_PIPE_MAXSIZE > 255
typedef uint16_t lc_size_t; /* 16-bit index */
#else
typedef uint8_t lc_size_t; /* 8-bit index */
#endif
/**************************************************************************** /****************************************************************************
* Public Type Definitions * Public Type Definitions
****************************************************************************/ ****************************************************************************/
@@ -120,8 +128,7 @@ struct local_conn_s
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 */
uint32_t lc_sndsize; /* Send buffer size */ lc_size_t lc_rcvsize; /* Receive buffer size */
uint32_t lc_rcvsize; /* Receive buffer size */
FAR struct local_conn_s * FAR struct local_conn_s *
lc_peer; /* Peer connection instance */ lc_peer; /* Peer connection instance */
@@ -456,7 +463,7 @@ ssize_t local_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
int local_send_preamble(FAR struct local_conn_s *conn, int local_send_preamble(FAR struct local_conn_s *conn,
FAR struct file *filep, FAR struct file *filep,
FAR const struct iovec *buf, FAR const struct iovec *buf,
size_t len); size_t len, size_t rcvsize);
/**************************************************************************** /****************************************************************************
* Name: local_send_packet * Name: local_send_packet
-1
View File
@@ -153,7 +153,6 @@ FAR struct local_conn_s *local_alloc(void)
*/ */
conn->lc_crefs = 1; conn->lc_crefs = 1;
conn->lc_sndsize = CONFIG_DEV_FIFO_SIZE;
conn->lc_rcvsize = CONFIG_DEV_FIFO_SIZE; conn->lc_rcvsize = CONFIG_DEV_FIFO_SIZE;
#ifdef CONFIG_NET_LOCAL_STREAM #ifdef CONFIG_NET_LOCAL_STREAM
+1 -3
View File
@@ -88,9 +88,7 @@ static int inline local_stream_connect(FAR struct local_conn_s *client,
/* Create the FIFOs needed for the connection */ /* Create the FIFOs needed for the connection */
ret = local_create_fifos(client, ret = local_create_fifos(client, server->lc_rcvsize, client->lc_rcvsize);
MIN(client->lc_sndsize, server->lc_rcvsize),
MIN(client->lc_rcvsize, server->lc_sndsize));
if (ret < 0) if (ret < 0)
{ {
nerr("ERROR: Failed to create FIFOs for %s: %d\n", nerr("ERROR: Failed to create FIFOs for %s: %d\n",
+2 -2
View File
@@ -687,7 +687,7 @@ int local_open_receiver(FAR struct local_conn_s *conn, bool nonblock)
*/ */
ret = local_set_pollinthreshold(&conn->lc_infile, ret = local_set_pollinthreshold(&conn->lc_infile,
2 * sizeof(uint16_t)); 2 * sizeof(lc_size_t));
} }
} }
@@ -730,7 +730,7 @@ int local_open_sender(FAR struct local_conn_s *conn, FAR const char *path,
*/ */
ret = local_set_polloutthreshold(&conn->lc_outfile, ret = local_set_polloutthreshold(&conn->lc_outfile,
2 * sizeof(uint16_t)); 2 * sizeof(lc_size_t));
} }
} }
+2 -8
View File
@@ -369,17 +369,11 @@ psock_dgram_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
size_t readlen; size_t readlen;
size_t pathlen; size_t pathlen;
bool bclose = false; bool bclose = false;
uint16_t addrlen; lc_size_t addrlen;
uint16_t pktlen; lc_size_t pktlen;
int offset = 0; int offset = 0;
int ret; int ret;
/* We keep packet sizes in a uint16_t, so there is a upper limit to the
* 'len' that can be supported.
*/
DEBUGASSERT(len <= UINT16_MAX);
/* Verify that this is a bound, un-connected peer socket */ /* Verify that this is a bound, un-connected peer socket */
if (conn->lc_state != LOCAL_STATE_BOUND && if (conn->lc_state != LOCAL_STATE_BOUND &&
+7 -3
View File
@@ -261,6 +261,7 @@ static ssize_t local_sendto(FAR struct socket *psock,
{ {
#ifdef CONFIG_NET_LOCAL_DGRAM #ifdef CONFIG_NET_LOCAL_DGRAM
FAR struct local_conn_s *conn = psock->s_conn; FAR struct local_conn_s *conn = psock->s_conn;
FAR struct local_conn_s *server;
FAR const struct sockaddr_un *unaddr = (FAR const struct sockaddr_un *)to; FAR const struct sockaddr_un *unaddr = (FAR const struct sockaddr_un *)to;
ssize_t ret; ssize_t ret;
@@ -307,7 +308,9 @@ static ssize_t local_sendto(FAR struct socket *psock,
} }
net_lock(); net_lock();
if (local_findconn(conn, unaddr) == NULL)
server = local_findconn(conn, unaddr);
if (server == NULL)
{ {
net_unlock(); net_unlock();
nerr("ERROR: No such file or directory\n"); nerr("ERROR: No such file or directory\n");
@@ -335,7 +338,7 @@ static ssize_t local_sendto(FAR struct socket *psock,
* REVISIT: Or should be just make sure that it already exists? * REVISIT: Or should be just make sure that it already exists?
*/ */
ret = local_create_halfduplex(conn, unaddr->sun_path, conn->lc_sndsize); ret = local_create_halfduplex(conn, unaddr->sun_path, server->lc_rcvsize);
if (ret < 0) if (ret < 0)
{ {
nerr("ERROR: Failed to create FIFO for %s: %zd\n", nerr("ERROR: Failed to create FIFO for %s: %zd\n",
@@ -358,7 +361,8 @@ static ssize_t local_sendto(FAR struct socket *psock,
/* Send the preamble */ /* Send the preamble */
ret = local_send_preamble(conn, &conn->lc_outfile, buf, len); ret = local_send_preamble(conn, &conn->lc_outfile, buf, len,
server->lc_rcvsize);
if (ret < 0) if (ret < 0)
{ {
nerr("ERROR: Failed to send the preamble: %zd\n", ret); nerr("ERROR: Failed to send the preamble: %zd\n", ret);
+28 -26
View File
@@ -114,43 +114,45 @@ static int local_fifo_write(FAR struct file *filep, FAR const uint8_t *buf,
int local_send_preamble(FAR struct local_conn_s *conn, int local_send_preamble(FAR struct local_conn_s *conn,
FAR struct file *filep, FAR struct file *filep,
FAR const struct iovec *buf, FAR const struct iovec *buf,
size_t len) size_t len, size_t rcvsize)
{ {
FAR const struct iovec *end = buf + len; FAR const struct iovec *end = buf + len;
FAR const struct iovec *iov; FAR const struct iovec *iov;
int ret; int ret;
uint16_t len16 = strlen(conn->lc_path); lc_size_t pathlen;
lc_size_t pktlen;
ret = local_fifo_write(&conn->lc_outfile, (FAR const uint8_t *)&len16, /* Send the packet length */
sizeof(uint16_t));
if (ret != sizeof(uint16_t)) for (pktlen = 0, iov = buf; iov != end; iov++)
{
pktlen += iov->iov_len;
}
if (pktlen > rcvsize - sizeof(lc_size_t))
{
nerr("ERROR: Packet is too big: %d\n", pktlen);
return -EMSGSIZE;
}
pathlen = strlen(conn->lc_path);
ret = local_fifo_write(&conn->lc_outfile, (FAR const uint8_t *)&pathlen,
sizeof(lc_size_t));
if (ret != sizeof(lc_size_t))
{ {
nerr("ERROR: local send path length failed ret: %d\n", ret); nerr("ERROR: local send path length failed ret: %d\n", ret);
return ret; return ret;
} }
/* Send the packet length */ ret = local_fifo_write(filep, (FAR const uint8_t *)&pktlen,
sizeof(lc_size_t));
for (len16 = 0, iov = buf; iov != end; iov++) if (ret != sizeof(lc_size_t))
{
len16 += iov->iov_len;
}
if (len16 > conn->lc_sndsize - sizeof(uint32_t))
{
nerr("ERROR: Packet is too big: %d\n", len16);
return -EMSGSIZE;
}
ret = local_fifo_write(filep, (FAR const uint8_t *)&len16,
sizeof(uint16_t));
if (ret != sizeof(uint16_t))
{ {
return ret; return ret;
} }
return local_fifo_write(&conn->lc_outfile, (uint8_t *)conn->lc_path, return local_fifo_write(&conn->lc_outfile, (uint8_t *)conn->lc_path,
strlen(conn->lc_path)); pathlen);
} }
/**************************************************************************** /****************************************************************************
@@ -176,9 +178,9 @@ int local_send_packet(FAR struct file *filep, FAR const struct iovec *buf,
FAR const struct iovec *end = buf + len; FAR const struct iovec *end = buf + len;
FAR const struct iovec *iov; FAR const struct iovec *iov;
int ret = -EINVAL; int ret = -EINVAL;
uint16_t len16; lc_size_t sendlen;
for (len16 = 0, iov = buf; iov != end; iov++) for (sendlen = 0, iov = buf; iov != end; iov++)
{ {
ret = local_fifo_write(filep, iov->iov_base, iov->iov_len); ret = local_fifo_write(filep, iov->iov_base, iov->iov_len);
if (ret < 0) if (ret < 0)
@@ -193,7 +195,7 @@ int local_send_packet(FAR struct file *filep, FAR const struct iovec *buf,
if (ret > 0) if (ret > 0)
{ {
len16 += ret; sendlen += ret;
if (ret != iov->iov_len) if (ret != iov->iov_len)
{ {
break; break;
@@ -201,5 +203,5 @@ int local_send_packet(FAR struct file *filep, FAR const struct iovec *buf,
} }
} }
return len16 > 0 ? len16 : ret; return sendlen > 0 ? sendlen : ret;
} }
+110 -31
View File
@@ -569,41 +569,51 @@ static int local_getsockopt(FAR struct socket *psock, int level, int option,
case SO_SNDBUF: case SO_SNDBUF:
{ {
int sendsize;
if (*value_len != sizeof(int)) if (*value_len != sizeof(int))
{ {
return -EINVAL; return -EINVAL;
} }
if (psock->s_type == SOCK_STREAM) if (conn->lc_peer)
{ {
*(FAR int *)value = conn->lc_sndsize; sendsize = conn->lc_peer->lc_rcvsize;
} }
else else
{ {
*(FAR int *)value = conn->lc_sndsize - sendsize = CONFIG_DEV_FIFO_SIZE;
sizeof(uint32_t) -
UNIX_PATH_MAX;
} }
#ifdef CONFIG_NET_LOCAL_DGRAM
if (psock->s_type == SOCK_DGRAM)
{
sendsize -= sizeof(lc_size_t) * 2 + UNIX_PATH_MAX;
}
#endif
*(FAR int *)value = sendsize;
return OK; return OK;
} }
case SO_RCVBUF: case SO_RCVBUF:
{ {
int recvsize;
if (*value_len != sizeof(int)) if (*value_len != sizeof(int))
{ {
return -EINVAL; return -EINVAL;
} }
if (psock->s_type == SOCK_STREAM) recvsize = conn->lc_rcvsize;
#ifdef CONFIG_NET_LOCAL_DGRAM
if (psock->s_type == SOCK_DGRAM)
{ {
*(FAR int *)value = conn->lc_rcvsize; recvsize -= sizeof(lc_size_t) * 2 + UNIX_PATH_MAX;
}
else
{
*(FAR int *)value = conn->lc_rcvsize -
sizeof(uint32_t) -
UNIX_PATH_MAX;
} }
#endif
*(FAR int *)value = recvsize;
return OK; return OK;
} }
} }
@@ -647,32 +657,102 @@ static int local_setsockopt(FAR struct socket *psock, int level, int option,
{ {
case SO_SNDBUF: case SO_SNDBUF:
{ {
if (psock->s_type == SOCK_STREAM) int ret = OK;
int rcvsize;
if (value_len < sizeof(int))
{ {
conn->lc_sndsize = *(FAR const int *)value; return -EINVAL;
} }
else
net_lock();
/* Only SOCK_STREAM sockets need set the send buffer size */
if (conn->lc_peer)
{ {
conn->lc_sndsize = *(FAR const int *)value + rcvsize = MIN(*(FAR const int *)value,
sizeof(uint32_t) + CONFIG_DEV_PIPE_MAXSIZE);
UNIX_PATH_MAX; if (conn->lc_peer->lc_infile.f_inode != NULL)
{
ret = file_ioctl(&conn->lc_peer->lc_infile,
PIPEIOC_SETSIZE, rcvsize);
}
if (ret == OK)
{
conn->lc_peer->lc_rcvsize = rcvsize;
}
} }
return OK; #ifdef CONFIG_NET_LOCAL_STREAM
else if (psock->s_type == SOCK_STREAM)
{
ret = -ENOTCONN;
}
#endif
net_unlock();
return ret;
} }
case SO_RCVBUF: case SO_RCVBUF:
{ {
if (psock->s_type == SOCK_STREAM) int ret = OK;
int rcvsize;
if (value_len < sizeof(int))
{ {
conn->lc_rcvsize = *(FAR const int *)value; return -EINVAL;
} }
else
net_lock();
rcvsize = *(FAR const int *)value;
#ifdef CONFIG_NET_LOCAL_DGRAM
if (psock->s_type == SOCK_DGRAM)
{ {
conn->lc_rcvsize = *(FAR const int *)value + rcvsize += sizeof(lc_size_t) * 2 + UNIX_PATH_MAX;
sizeof(uint32_t) +
UNIX_PATH_MAX;
} }
return OK; #endif
rcvsize = MIN(rcvsize, CONFIG_DEV_PIPE_MAXSIZE);
if (conn->lc_infile.f_inode != NULL)
{
ret = file_ioctl(&conn->lc_infile, PIPEIOC_SETSIZE,
rcvsize);
}
#ifdef CONFIG_NET_LOCAL_DGRAM
else if (psock->s_type == SOCK_DGRAM &&
conn->lc_state == LOCAL_STATE_BOUND)
{
ret = local_create_halfduplex(conn, conn->lc_path,
rcvsize);
if (ret >= 0)
{
ret = local_open_receiver(conn, true);
if (ret >= 0)
{
ret = file_ioctl(&conn->lc_infile, PIPEIOC_SETSIZE,
rcvsize);
}
if (conn->lc_infile.f_inode != NULL)
{
file_close(&conn->lc_infile);
}
}
}
#endif
if (ret == OK)
{
conn->lc_rcvsize = rcvsize;
}
net_unlock();
return ret;
} }
} }
} }
@@ -973,9 +1053,8 @@ static int local_socketpair(FAR struct socket *psocks[2])
/* Create the FIFOs needed for the connection */ /* Create the FIFOs needed for the connection */
ret = local_create_fifos(conns[0], ret = local_create_fifos(conns[0], conns[0]->lc_rcvsize,
MIN(conns[0]->lc_sndsize, conns[1]->lc_rcvsize), conns[1]->lc_rcvsize);
MIN(conns[0]->lc_rcvsize, conns[1]->lc_sndsize));
if (ret < 0) if (ret < 0)
{ {
goto errout; goto errout;
@@ -1023,7 +1102,7 @@ static int local_socketpair(FAR struct socket *psocks[2])
{ {
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
ret = local_set_pollthreshold(conns[i], sizeof(uint16_t)); ret = local_set_pollthreshold(conns[i], sizeof(lc_size_t));
if (ret < 0) if (ret < 0)
{ {
goto errout; goto errout;