net/tcp: Extended support for sending to non-blocking tcp sockets.
This commit is contained in:
parent
161fb98b11
commit
303e6499bd
@ -1416,6 +1416,25 @@ void tcp_wrbuffer_initialize(void);
|
|||||||
struct tcp_wrbuffer_s;
|
struct tcp_wrbuffer_s;
|
||||||
|
|
||||||
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void);
|
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: tcp_wrbuffer_tryalloc
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Try to allocate a TCP write buffer by taking a pre-allocated buffer from
|
||||||
|
* the free list. This function is called from TCP logic when a buffer
|
||||||
|
* of TCP data is about to be sent if the socket is non-blocking. Returns
|
||||||
|
* immediately if allocation fails.
|
||||||
|
*
|
||||||
|
* Input parameters:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* Called from user logic with the network locked.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_tryalloc(void);
|
||||||
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
|
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -1086,13 +1086,21 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
net_lock();
|
net_lock();
|
||||||
|
if (_SS_ISNONBLOCK(psock->s_flags))
|
||||||
|
{
|
||||||
|
wrb = tcp_wrbuffer_tryalloc();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
wrb = tcp_wrbuffer_alloc();
|
wrb = tcp_wrbuffer_alloc();
|
||||||
if (!wrb)
|
}
|
||||||
|
|
||||||
|
if (wrb == NULL)
|
||||||
{
|
{
|
||||||
/* A buffer allocation error occurred */
|
/* A buffer allocation error occurred */
|
||||||
|
|
||||||
nerr("ERROR: Failed to allocate write buffer\n");
|
nerr("ERROR: Failed to allocate write buffer\n");
|
||||||
ret = -ENOMEM;
|
ret = _SS_ISNONBLOCK(psock->s_flags) ? -EAGAIN : -ENOMEM;
|
||||||
goto errout_with_lock;
|
goto errout_with_lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1110,7 +1118,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
|
|||||||
/* A buffer allocation error occurred */
|
/* A buffer allocation error occurred */
|
||||||
|
|
||||||
nerr("ERROR: Failed to allocate callback\n");
|
nerr("ERROR: Failed to allocate callback\n");
|
||||||
ret = -ENOMEM;
|
ret = _SS_ISNONBLOCK(psock->s_flags) ? -EAGAIN : -ENOMEM;
|
||||||
goto errout_with_wrb;
|
goto errout_with_wrb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1132,7 +1140,33 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf,
|
|||||||
|
|
||||||
if (_SS_ISNONBLOCK(psock->s_flags))
|
if (_SS_ISNONBLOCK(psock->s_flags))
|
||||||
{
|
{
|
||||||
|
/* The return value from TCP_WBTRYCOPYIN is either OK or
|
||||||
|
* -ENOMEM if less than the entire data chunk could be allocated.
|
||||||
|
* If -ENOMEM is returned, check if at least a part of the data
|
||||||
|
* chunk was allocated. If more than zero bytes were sent
|
||||||
|
* we return that number and let the caller deal with sending the
|
||||||
|
* remaining data.
|
||||||
|
*/
|
||||||
|
|
||||||
result = TCP_WBTRYCOPYIN(wrb, (FAR uint8_t *)buf, len);
|
result = TCP_WBTRYCOPYIN(wrb, (FAR uint8_t *)buf, len);
|
||||||
|
if (result == -ENOMEM)
|
||||||
|
{
|
||||||
|
if (TCP_WBPKTLEN(wrb) > 0)
|
||||||
|
{
|
||||||
|
ninfo("INFO: Allocated part of the requested data\n");
|
||||||
|
result = TCP_WBPKTLEN(wrb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nerr("ERROR: Failed to add data to the I/O buffer chain\n");
|
||||||
|
ret = -EWOULDBLOCK;
|
||||||
|
goto errout_with_wrb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* net/tcp/tcp_wrbuffer.c
|
* net/tcp/tcp_wrbuffer.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007-2009, 2013-2014 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007-2009, 2013-2014, 2018 Gregory Nutt. All rights
|
||||||
|
* reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
* Jason Jiang <jasonj@live.cn>
|
* Jason Jiang <jasonj@live.cn>
|
||||||
*
|
*
|
||||||
@ -169,6 +170,66 @@ FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void)
|
|||||||
return wrb;
|
return wrb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: tcp_wrbuffer_tryalloc
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Try to allocate a TCP write buffer by taking a pre-allocated buffer from
|
||||||
|
* the free list. This function is called from TCP logic when a buffer
|
||||||
|
* of TCP data is about to be sent on a non-blocking socket. Returns
|
||||||
|
* immediately if the allocation failed.
|
||||||
|
*
|
||||||
|
* Input parameters:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* Called from user logic with the network locked. Will return if no buffer
|
||||||
|
* is available.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_tryalloc(void)
|
||||||
|
{
|
||||||
|
FAR struct tcp_wrbuffer_s *wrb;
|
||||||
|
|
||||||
|
/* We need to allocate two things: (1) A write buffer structure and (2)
|
||||||
|
* at least one I/O buffer to start the chain.
|
||||||
|
*
|
||||||
|
* Allocate the write buffer structure first then the IOBG. In order to
|
||||||
|
* avoid deadlocks, we will need to free the IOB first, then the write
|
||||||
|
* buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (tcp_wrbuffer_test() == OK)
|
||||||
|
{
|
||||||
|
DEBUGVERIFY(net_lockedwait(&g_wrbuffer.sem));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, we are guaranteed to have a write buffer structure reserved
|
||||||
|
* for us in the free list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
wrb = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers);
|
||||||
|
DEBUGASSERT(wrb);
|
||||||
|
memset(wrb, 0, sizeof(struct tcp_wrbuffer_s));
|
||||||
|
|
||||||
|
/* Now get the first I/O buffer for the write buffer structure */
|
||||||
|
|
||||||
|
wrb->wb_iob = iob_tryalloc(false);
|
||||||
|
if (!wrb->wb_iob)
|
||||||
|
{
|
||||||
|
nerr("ERROR: Failed to allocate I/O buffer\n");
|
||||||
|
tcp_wrbuffer_release(wrb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrb;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: tcp_wrbuffer_release
|
* Name: tcp_wrbuffer_release
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user