This commit adds an as-of-yet untested implemented of UDP write buffering.
Squashed commit of the following: net/udp: Address most of the issues with UDP write buffering. There is a remaining issue with handling one network going down in a multi-network environment. None of this has been test but it is certainly ready for test. Hence, the feature is marked EXPERIMENTAL. net/udp: Some baby steps toward a corrected write buffering design. net/udp: Remove pesky write buffer macros. Eliminate trailing space at the end of lines. net/udp: A little more UDP write buffering logic. Still at least on big gaping hole in the design. net/udp: Undefined CONFIG_NET_SENDTO_TIMEOUT. net/udp: Crude, naive port of the TCP write buffering logic into UDP. This commit is certainly non-functional and is simply a starting point for the implementatin of UDP write buffering. net/udp: Rename udp/udp_psock_sendto.c udp/udp_psock_sendto_unbuffered.c.
This commit is contained in:
parent
0406fff888
commit
fef255e5be
@ -208,8 +208,8 @@ struct socket
|
|||||||
|
|
||||||
FAR const struct sock_intf_s *s_sockif;
|
FAR const struct sock_intf_s *s_sockif;
|
||||||
|
|
||||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) || defined(CONFIG_NET_UDP_WRITE_BUFFERS)
|
||||||
/* Callback instance for TCP send */
|
/* Callback instance for TCP send() or UDP sendto() */
|
||||||
|
|
||||||
FAR struct devif_callback_s *s_sndcb;
|
FAR struct devif_callback_s *s_sndcb;
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,9 +16,9 @@ if MM_IOB
|
|||||||
|
|
||||||
config IOB_NBUFFERS
|
config IOB_NBUFFERS
|
||||||
int "Number of pre-allocated I/O buffers"
|
int "Number of pre-allocated I/O buffers"
|
||||||
default 24 if (NET_TCP_WRITE_BUFFERS && !NET_TCP_READAHEAD) || (!NET_TCP_WRITE_BUFFERS && NET_TCP_READAHEAD)
|
default 24 if (NET_WRITE_BUFFERS && !NET_READAHEAD) || (!NET_WRITE_BUFFERS && NET_READAHEAD)
|
||||||
default 36 if NET_TCP_WRITE_BUFFERS && NET_TCP_READAHEAD
|
default 36 if NET_WRITE_BUFFERS && NET_READAHEAD
|
||||||
default 8 if !NET_TCP_WRITE_BUFFERS && !NET_TCP_READAHEAD
|
default 8 if !NET_WRITE_BUFFERS && !NET_READAHEAD
|
||||||
---help---
|
---help---
|
||||||
Each packet is represented by a series of small I/O buffers in a
|
Each packet is represented by a series of small I/O buffers in a
|
||||||
chain. This setting determines the number of preallocated I/O
|
chain. This setting determines the number of preallocated I/O
|
||||||
@ -34,8 +34,8 @@ config IOB_BUFSIZE
|
|||||||
|
|
||||||
config IOB_NCHAINS
|
config IOB_NCHAINS
|
||||||
int "Number of pre-allocated I/O buffer chain heads"
|
int "Number of pre-allocated I/O buffer chain heads"
|
||||||
default 0 if !NET_TCP_READAHEAD && !NET_UDP_READAHEAD
|
default 0 if !NET_READAHEAD && !NET_UDP_READAHEAD
|
||||||
default 8 if NET_TCP_READAHEAD || NET_UDP_READAHEAD
|
default 8 if NET_READAHEAD || NET_UDP_READAHEAD
|
||||||
---help---
|
---help---
|
||||||
These tiny nodes are used as "containers" to support queueing of
|
These tiny nodes are used as "containers" to support queueing of
|
||||||
I/O buffer chains. This will limit the number of I/O transactions
|
I/O buffer chains. This will limit the number of I/O transactions
|
||||||
@ -49,8 +49,8 @@ config IOB_NCHAINS
|
|||||||
|
|
||||||
config IOB_THROTTLE
|
config IOB_THROTTLE
|
||||||
int "I/O buffer throttle value"
|
int "I/O buffer throttle value"
|
||||||
default 0 if !NET_TCP_WRITE_BUFFERS || !NET_TCP_READAHEAD
|
default 0 if !NET_WRITE_BUFFERS || !NET_READAHEAD
|
||||||
default 8 if NET_TCP_WRITE_BUFFERS && NET_TCP_READAHEAD
|
default 8 if NET_WRITE_BUFFERS && NET_READAHEAD
|
||||||
---help---
|
---help---
|
||||||
TCP write buffering and read-ahead buffer use the same pool of free
|
TCP write buffering and read-ahead buffer use the same pool of free
|
||||||
I/O buffers. In order to prevent uncontrolled incoming TCP packets
|
I/O buffers. In order to prevent uncontrolled incoming TCP packets
|
||||||
|
@ -11,6 +11,14 @@ config ARCH_HAVE_PHY
|
|||||||
bool
|
bool
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config NET_WRITE_BUFFERS
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
|
||||||
|
config NET_READAHEAD
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
|
||||||
config NET
|
config NET
|
||||||
bool "Networking support"
|
bool "Networking support"
|
||||||
default n
|
default n
|
||||||
|
@ -1146,7 +1146,7 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||||||
#if defined(CONFIG_NET_6LOWPAN)
|
#if defined(CONFIG_NET_6LOWPAN)
|
||||||
/* Try 6LoWPAN UDP packet sendto() */
|
/* Try 6LoWPAN UDP packet sendto() */
|
||||||
|
|
||||||
nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, tolen);
|
nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, minlen);
|
||||||
|
|
||||||
#ifdef NET_UDP_HAVE_STACK
|
#ifdef NET_UDP_HAVE_STACK
|
||||||
if (nsent < 0)
|
if (nsent < 0)
|
||||||
|
@ -172,6 +172,10 @@ void net_setup(void)
|
|||||||
/* Initialize the UDP connection structures */
|
/* Initialize the UDP connection structures */
|
||||||
|
|
||||||
udp_initialize();
|
udp_initialize();
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
|
udp_wrbuffer_initialize();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_NET_IGMP
|
#ifdef CONFIG_NET_IGMP
|
||||||
|
@ -105,7 +105,7 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock)
|
|||||||
psock->s_domain = domain;
|
psock->s_domain = domain;
|
||||||
psock->s_type = type;
|
psock->s_type = type;
|
||||||
psock->s_conn = NULL;
|
psock->s_conn = NULL;
|
||||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) || defined(CONFIG_NET_UDP_WRITE_BUFFERS)
|
||||||
psock->s_sndcb = NULL;
|
psock->s_sndcb = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ config NET_MAX_LISTENPORTS
|
|||||||
config NET_TCP_READAHEAD
|
config NET_TCP_READAHEAD
|
||||||
bool "Enable TCP/IP read-ahead buffering"
|
bool "Enable TCP/IP read-ahead buffering"
|
||||||
default y
|
default y
|
||||||
|
select NET_READAHEAD
|
||||||
select MM_IOB
|
select MM_IOB
|
||||||
---help---
|
---help---
|
||||||
Read-ahead buffers allows buffering of TCP/IP packets when there is no
|
Read-ahead buffers allows buffering of TCP/IP packets when there is no
|
||||||
@ -91,6 +92,7 @@ endif # NET_TCP_READAHEAD
|
|||||||
config NET_TCP_WRITE_BUFFERS
|
config NET_TCP_WRITE_BUFFERS
|
||||||
bool "Enable TCP/IP write buffering"
|
bool "Enable TCP/IP write buffering"
|
||||||
default n
|
default n
|
||||||
|
select NET_WRITE_BUFFERS
|
||||||
select MM_IOB
|
select MM_IOB
|
||||||
---help---
|
---help---
|
||||||
Write buffers allows buffering of ongoing TCP/IP packets, providing
|
Write buffers allows buffering of ongoing TCP/IP packets, providing
|
||||||
@ -105,7 +107,7 @@ config NET_TCP_NWRBCHAINS
|
|||||||
int "Number of pre-allocated I/O buffer chain heads"
|
int "Number of pre-allocated I/O buffer chain heads"
|
||||||
default 8
|
default 8
|
||||||
---help---
|
---help---
|
||||||
These tiny nodes are used as "containers" to support queueing of
|
These tiny nodes are used as "containers" to support queuing of
|
||||||
TCP write buffers. This setting will limit the number of TCP write
|
TCP write buffers. This setting will limit the number of TCP write
|
||||||
operations that can be "in-flight" at any give time. So a good
|
operations that can be "in-flight" at any give time. So a good
|
||||||
choice for this value would be the same as the maximum number of
|
choice for this value would be the same as the maximum number of
|
||||||
|
@ -44,7 +44,57 @@ config NET_BROADCAST
|
|||||||
config NET_UDP_READAHEAD
|
config NET_UDP_READAHEAD
|
||||||
bool "Enable UDP/IP read-ahead buffering"
|
bool "Enable UDP/IP read-ahead buffering"
|
||||||
default y
|
default y
|
||||||
|
select NET_READAHEAD
|
||||||
select MM_IOB
|
select MM_IOB
|
||||||
|
|
||||||
|
config NET_UDP_WRITE_BUFFERS
|
||||||
|
bool "Enable UDP/IP write buffering"
|
||||||
|
default n
|
||||||
|
select NET_WRITE_BUFFERS
|
||||||
|
select MM_IOB
|
||||||
|
depends on EXPERIMENTAL
|
||||||
|
---help---
|
||||||
|
Write buffers allows buffering of ongoing UDP/IP packets, providing
|
||||||
|
for higher performance, streamed output.
|
||||||
|
|
||||||
|
You might want to disable UDP/IP write buffering on a highly memory
|
||||||
|
memory constrained system where there are no performance issues.
|
||||||
|
|
||||||
|
if NET_UDP_WRITE_BUFFERS
|
||||||
|
|
||||||
|
config NET_UDP_NWRBCHAINS
|
||||||
|
int "Number of pre-allocated I/O buffer chain heads"
|
||||||
|
default 8
|
||||||
|
---help---
|
||||||
|
These tiny nodes are used as "containers" to support queuing of
|
||||||
|
UDP write buffers. This setting will limit the number of UDP write
|
||||||
|
operations that can be "in-flight" at any give time. So a good
|
||||||
|
choice for this value would be the same as the maximum number of
|
||||||
|
UDP connections.
|
||||||
|
|
||||||
|
config NET_UDP_WRBUFFER_DEBUG
|
||||||
|
bool "Force write buffer debug"
|
||||||
|
default n
|
||||||
|
depends on DEBUG_FEATURES
|
||||||
|
select IOB_DEBUG
|
||||||
|
---help---
|
||||||
|
This option will force debug output from UDP write buffer logic,
|
||||||
|
even without network debug output. This is not normally something
|
||||||
|
that would want to do but is convenient if you are debugging the
|
||||||
|
write buffer logic and do not want to get overloaded with other
|
||||||
|
network-related debug output.
|
||||||
|
|
||||||
|
config NET_UDP_WRBUFFER_DUMP
|
||||||
|
bool "Force write buffer dump"
|
||||||
|
default n
|
||||||
|
depends on DEBUG_NET || NET_UDP_WRBUFFER_DEBUG
|
||||||
|
select IOB_DEBUG
|
||||||
|
---help---
|
||||||
|
Dump the contents of the write buffers. You do not want to do this
|
||||||
|
unless you really want to analyze the write buffer transfers in
|
||||||
|
detail.
|
||||||
|
|
||||||
|
endif # NET_UDP_WRITE_BUFFERS
|
||||||
|
|
||||||
endif # NET_UDP && !NET_UDP_NO_STACK
|
endif # NET_UDP && !NET_UDP_NO_STACK
|
||||||
endmenu # UDP Networking
|
endmenu # UDP Networking
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
############################################################################
|
############################################################################
|
||||||
# net/udp/Make.defs
|
# net/udp/Make.defs
|
||||||
#
|
#
|
||||||
# Copyright (C) 2014-2015 Gregory Nutt. All rights reserved.
|
# Copyright (C) 2014-2015, 2018 Gregory Nutt. All rights reserved.
|
||||||
# Author: Gregory Nutt <gnutt@nuttx.org>
|
# Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# Redistribution and use in source and binary forms, with or without
|
||||||
@ -40,7 +40,13 @@ ifneq ($(CONFIG_NET_UDP_NO_STACK),y)
|
|||||||
|
|
||||||
# Socket layer
|
# Socket layer
|
||||||
|
|
||||||
NET_CSRCS += udp_psock_send.c udp_psock_sendto.c
|
NET_CSRCS += udp_psock_send.c
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_NET_UDP_WRITE_BUFFERS),y)
|
||||||
|
SOCK_CSRCS += udp_psock_sendto_buffered.c
|
||||||
|
else
|
||||||
|
SOCK_CSRCS += udp_psock_sendto_unbuffered.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(CONFIG_DISABLE_POLL),y)
|
ifneq ($(CONFIG_DISABLE_POLL),y)
|
||||||
ifeq ($(CONFIG_NET_UDP_READAHEAD),y)
|
ifeq ($(CONFIG_NET_UDP_READAHEAD),y)
|
||||||
@ -53,6 +59,15 @@ endif
|
|||||||
NET_CSRCS += udp_conn.c udp_devpoll.c udp_send.c udp_input.c udp_finddev.c
|
NET_CSRCS += udp_conn.c udp_devpoll.c udp_send.c udp_input.c udp_finddev.c
|
||||||
NET_CSRCS += udp_callback.c udp_ipselect.c
|
NET_CSRCS += udp_callback.c udp_ipselect.c
|
||||||
|
|
||||||
|
# UDP write buffering
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_NET_UDP_WRITE_BUFFERS),y)
|
||||||
|
NET_CSRCS += udp_wrbuffer.c
|
||||||
|
ifeq ($(CONFIG_DEBUG_FEATURES),y)
|
||||||
|
NET_CSRCS += udp_wrbuffer_dump.c
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
# Include UDP build support
|
# Include UDP build support
|
||||||
|
|
||||||
DEPPATH += --dep-path udp
|
DEPPATH += --dep-path udp
|
||||||
|
129
net/udp/udp.h
129
net/udp/udp.h
@ -1,7 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* net/udp/udp.h
|
* net/udp/udp.h
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014-2015 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2014-2015, 2018 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -45,6 +45,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <queue.h>
|
#include <queue.h>
|
||||||
|
|
||||||
|
#include <nuttx/clock.h>
|
||||||
#include <nuttx/net/ip.h>
|
#include <nuttx/net/ip.h>
|
||||||
|
|
||||||
#ifdef CONFIG_NET_UDP_READAHEAD
|
#ifdef CONFIG_NET_UDP_READAHEAD
|
||||||
@ -66,6 +67,17 @@
|
|||||||
# define HAVE_UDP_POLL
|
# define HAVE_UDP_POLL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
|
/* UDP write buffer dump macros */
|
||||||
|
|
||||||
|
# ifdef CONFIG_DEBUG_FEATURES
|
||||||
|
# define UDPWB_DUMP(msg,wrb,len,offset) \
|
||||||
|
udp_wrbuffer_dump(msg,wrb,len,offset)
|
||||||
|
# else
|
||||||
|
# define UDPWB_DUMP(msg,wrb,len,offset)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Allocate a new UDP data callback */
|
/* Allocate a new UDP data callback */
|
||||||
|
|
||||||
#define udp_callback_alloc(dev,conn) \
|
#define udp_callback_alloc(dev,conn) \
|
||||||
@ -102,11 +114,38 @@ struct udp_conn_s
|
|||||||
struct iob_queue_s readahead; /* Read-ahead buffering */
|
struct iob_queue_s readahead; /* Read-ahead buffering */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||||
|
/* Write buffering
|
||||||
|
*
|
||||||
|
* write_q - The queue of unsent I/O buffers. The head of this
|
||||||
|
* list may be partially sent. FIFO ordering.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sq_queue_t write_q; /* Write buffering for UDP packets */
|
||||||
|
FAR struct net_driver_s *dev; /* Last device */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Defines the list of UDP callbacks */
|
/* Defines the list of UDP callbacks */
|
||||||
|
|
||||||
FAR struct devif_callback_s *list;
|
FAR struct devif_callback_s *list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* This structure supports UDP write buffering. It is simply a container
|
||||||
|
* for a IOB list and associated destination address.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
|
struct udp_wrbuffer_s
|
||||||
|
{
|
||||||
|
sq_entry_t wb_node; /* Supports a singly linked list */
|
||||||
|
union ip_addr_u wb_dest; /* Destination address */
|
||||||
|
#ifdef CONFIG_NET_SOCKOPTS
|
||||||
|
systime_t wb_start; /* Start time for timeout calculation */
|
||||||
|
#endif
|
||||||
|
struct iob_s *wb_iob; /* Head of the I/O buffer chain */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Data
|
* Public Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -291,6 +330,92 @@ void udp_poll(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn);
|
|||||||
|
|
||||||
void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn);
|
void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: udp_wrbuffer_initialize
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Initialize the list of free write buffers
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* Called once early initialization.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
|
void udp_wrbuffer_initialize(void);
|
||||||
|
#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: udp_wrbuffer_alloc
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Allocate a UDP write buffer by taking a pre-allocated buffer from
|
||||||
|
* the free list. This function is called from UDP logic when a buffer
|
||||||
|
* of UDP data is about to sent
|
||||||
|
*
|
||||||
|
* Input parameters:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* Called from user logic with the network locked.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
|
struct udp_wrbuffer_s;
|
||||||
|
|
||||||
|
FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void);
|
||||||
|
#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: udp_wrbuffer_release
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Release a UDP write buffer by returning the buffer to the free list.
|
||||||
|
* This function is called from user logic after it is consumed the
|
||||||
|
* buffered data.
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* Called from network stack logic with the network stack locked
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
|
void udp_wrbuffer_release(FAR struct udp_wrbuffer_s *wrb);
|
||||||
|
#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: udp_wrbuffer_test
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Check if there is room in the write buffer. Does not reserve any space.
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
|
int udp_wrbuffer_test(void);
|
||||||
|
#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: udp_wrbuffer_dump
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Dump the contents of a write buffer.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
|
#ifdef CONFIG_DEBUG_FEATURES
|
||||||
|
void udp_wrbuffer_dump(FAR const char *msg, FAR struct udp_wrbuffer_s *wrb,
|
||||||
|
unsigned int len, unsigned int offset);
|
||||||
|
#else
|
||||||
|
# define udp_wrbuffer_dump(msg,wrb)
|
||||||
|
#endif
|
||||||
|
#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: udp_ipv4_input
|
* Name: udp_ipv4_input
|
||||||
*
|
*
|
||||||
@ -495,7 +620,7 @@ int udp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds);
|
|||||||
* Teardown monitoring of events on an UDP/IP socket
|
* Teardown monitoring of events on an UDP/IP socket
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* psock - The TCP/IP socket of interest
|
* psock - The UDP/IP socket of interest
|
||||||
* fds - The structure describing the events to be monitored, OR NULL if
|
* fds - The structure describing the events to be monitored, OR NULL if
|
||||||
* this is a request to stop monitoring events.
|
* this is a request to stop monitoring events.
|
||||||
*
|
*
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* net/udp/udp_conn.c
|
* net/udp/udp_conn.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007-2009, 2011-2012, 2016 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007-2009, 2011-2012, 2016, 2018 Gregory Nutt. All rights
|
||||||
|
* reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Large parts of this file were leveraged from uIP logic:
|
* Large parts of this file were leveraged from uIP logic:
|
||||||
@ -485,6 +486,11 @@ FAR struct udp_conn_s *udp_alloc(uint8_t domain)
|
|||||||
conn->lport = 0;
|
conn->lport = 0;
|
||||||
conn->ttl = IP_TTL;
|
conn->ttl = IP_TTL;
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||||
|
/* Initialize the write buffer lists */
|
||||||
|
|
||||||
|
sq_init(&conn->write_q);
|
||||||
|
#endif
|
||||||
/* Enqueue the connection into the active list */
|
/* Enqueue the connection into the active list */
|
||||||
|
|
||||||
dq_addlast(&conn->node, &g_active_udp_connections);
|
dq_addlast(&conn->node, &g_active_udp_connections);
|
||||||
@ -505,6 +511,10 @@ FAR struct udp_conn_s *udp_alloc(uint8_t domain)
|
|||||||
|
|
||||||
void udp_free(FAR struct udp_conn_s *conn)
|
void udp_free(FAR struct udp_conn_s *conn)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
|
FAR struct udp_wrbuffer_s *wrbuffer;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The free list is protected by a semaphore (that behaves like a mutex). */
|
/* The free list is protected by a semaphore (that behaves like a mutex). */
|
||||||
|
|
||||||
DEBUGASSERT(conn->crefs == 0);
|
DEBUGASSERT(conn->crefs == 0);
|
||||||
@ -522,6 +532,15 @@ void udp_free(FAR struct udp_conn_s *conn)
|
|||||||
iob_free_queue(&conn->readahead);
|
iob_free_queue(&conn->readahead);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
|
/* Release any write buffers attached to the connection */
|
||||||
|
|
||||||
|
while ((wrbuffer = (struct udp_wrbuffer_s *)sq_remfirst(&conn->write_q)) != NULL)
|
||||||
|
{
|
||||||
|
udp_wrbuffer_release(wrbuffer);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Free the connection */
|
/* Free the connection */
|
||||||
|
|
||||||
dq_addlast(&conn->node, &g_free_udp_connections);
|
dq_addlast(&conn->node, &g_free_udp_connections);
|
||||||
|
821
net/udp/udp_psock_sendto_buffered.c
Normal file
821
net/udp/udp_psock_sendto_buffered.c
Normal file
@ -0,0 +1,821 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* net/udp/udp_send_buffered.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) && \
|
||||||
|
defined(CONFIG_NET_UDP_WRITE_BUFFERS)
|
||||||
|
|
||||||
|
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_NET_UDP_WRBUFFER_DEBUG)
|
||||||
|
/* Force debug output (from this file only) */
|
||||||
|
|
||||||
|
# undef CONFIG_DEBUG_NET
|
||||||
|
# define CONFIG_DEBUG_NET 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <arch/irq.h>
|
||||||
|
#include <nuttx/clock.h>
|
||||||
|
#include <nuttx/net/net.h>
|
||||||
|
#include <nuttx/mm/iob.h>
|
||||||
|
#include <nuttx/net/netdev.h>
|
||||||
|
#include <nuttx/net/arp.h>
|
||||||
|
#include <nuttx/net/udp.h>
|
||||||
|
|
||||||
|
#include "netdev/netdev.h"
|
||||||
|
#include "socket/socket.h"
|
||||||
|
#include "inet/inet.h"
|
||||||
|
#include "arp/arp.h"
|
||||||
|
#include "icmpv6/icmpv6.h"
|
||||||
|
#include "neighbor/neighbor.h"
|
||||||
|
#include "udp/udp.h"
|
||||||
|
#include "devif/devif.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
/* If both IPv4 and IPv6 support are both enabled, then we will need to build
|
||||||
|
* in some additional domain selection support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
|
||||||
|
# define NEED_IPDOMAIN_SUPPORT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UDPIPv4BUF ((struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN])
|
||||||
|
#define UDPIPv6BUF ((struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
|
||||||
|
|
||||||
|
/* Debug */
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_UDP_WRBUFFER_DUMP
|
||||||
|
# define BUF_DUMP(msg,buf,len) lib_dumpbuffer(msg,buf,len)
|
||||||
|
#else
|
||||||
|
# define BUF_DUMP(msg,buf,len)
|
||||||
|
# undef UDPWB_DUMP
|
||||||
|
# define UDPWB_DUMP(msg,wrb,len,offset)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Function Prototypes
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static inline void sendto_netdev_down(FAR struct socket *psock,
|
||||||
|
FAR struct udp_conn_s *conn);
|
||||||
|
|
||||||
|
#ifdef NEED_IPDOMAIN_SUPPORT
|
||||||
|
static inline void sendto_ipselect(FAR struct net_driver_s *dev,
|
||||||
|
FAR struct udp_conn_s *conn);
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_NET_ETHERNET
|
||||||
|
static inline bool sendto_addrcheck(FAR struct udp_conn_s *conn,
|
||||||
|
FAR struct net_driver_s *dev);
|
||||||
|
#else
|
||||||
|
# define sendto_addrcheck(c,d) (true)
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_NET_SOCKOPTS
|
||||||
|
static inline int sendto_timeout(FAR struct socket *psock,
|
||||||
|
FAR struct udp_conn_s *conn);
|
||||||
|
#endif
|
||||||
|
static int sendto_next_transfer(FAR struct socket *psock,
|
||||||
|
FAR struct udp_conn_s *conn);
|
||||||
|
static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
|
||||||
|
FAR void *pvconn, FAR void *pvpriv,
|
||||||
|
uint16_t flags);
|
||||||
|
static inline void sendto_txnotify(FAR struct socket *psock,
|
||||||
|
FAR struct udp_conn_s *conn);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sendto_netdev_down
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* The network device is down. Free all write buffers.
|
||||||
|
* REVISIT: Should only free write buffers associated with the device
|
||||||
|
* that went down.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* psock The socket structure
|
||||||
|
* conn The connection structure associated with the socket
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static inline void sendto_netdev_down(FAR struct socket *psock,
|
||||||
|
FAR struct udp_conn_s *conn)
|
||||||
|
{
|
||||||
|
FAR sq_entry_t *entry;
|
||||||
|
FAR sq_entry_t *next;
|
||||||
|
|
||||||
|
/* Do not allow any further callbacks */
|
||||||
|
|
||||||
|
if (psock->s_sndcb != NULL)
|
||||||
|
{
|
||||||
|
psock->s_sndcb->flags = 0;
|
||||||
|
psock->s_sndcb->event = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free all queued write buffers */
|
||||||
|
|
||||||
|
for (entry = sq_peek(&conn->write_q); entry; entry = next)
|
||||||
|
{
|
||||||
|
next = sq_next(entry);
|
||||||
|
udp_wrbuffer_release((FAR struct udp_wrbuffer_s *)entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset write buffering variables */
|
||||||
|
|
||||||
|
sq_init(&conn->write_q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sendto_ipselect
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* If both IPv4 and IPv6 support are enabled, then we will need to select
|
||||||
|
* which one to use when generating the outgoing packet. If only one
|
||||||
|
* domain is selected, then the setup is already in place and we need do
|
||||||
|
* nothing.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* dev - The structure of the network driver that caused the event
|
||||||
|
* psock - Socket state structure
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* The network is locked
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef NEED_IPDOMAIN_SUPPORT
|
||||||
|
static inline void sendto_ipselect(FAR struct net_driver_s *dev,
|
||||||
|
FAR struct udp_conn_s *conn)
|
||||||
|
{
|
||||||
|
/* Which domain the socket support */
|
||||||
|
|
||||||
|
if (conn->domain == PF_INET)
|
||||||
|
{
|
||||||
|
/* Select the IPv4 domain */
|
||||||
|
|
||||||
|
udp_ipv4_select(dev);
|
||||||
|
}
|
||||||
|
else /* if (conn->domain == PF_INET6) */
|
||||||
|
{
|
||||||
|
/* Select the IPv6 domain */
|
||||||
|
|
||||||
|
DEBUGASSERT(conn->domain == PF_INET6);
|
||||||
|
udp_ipv6_select(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sendto_addrcheck
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor
|
||||||
|
* tables. If not, then the send won't actually make it out... it will be
|
||||||
|
* replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6).
|
||||||
|
*
|
||||||
|
* NOTE 1: This could be an expensive check if there are a lot of
|
||||||
|
* entries in the ARP or Neighbor tables.
|
||||||
|
*
|
||||||
|
* NOTE 2: If we are actually harvesting IP addresses on incoming IP
|
||||||
|
* packets, then this check should not be necessary; the MAC mapping
|
||||||
|
* should already be in the ARP table in many cases (IPv4 only).
|
||||||
|
*
|
||||||
|
* NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP
|
||||||
|
* address mapping is already in the ARP table.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* conn - The UDP connection structure
|
||||||
|
* dev - Polling network device
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* true - The Ethernet MAC address is in the ARP or Neighbor table (OR
|
||||||
|
* the network device is not Ethernet).
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* The network is locked
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_ETHERNET
|
||||||
|
static inline bool sendto_addrcheck(FAR struct udp_conn_s *conn,
|
||||||
|
FAR struct net_driver_s *dev)
|
||||||
|
{
|
||||||
|
/* REVISIT: Could the MAC address not also be in a routing table? */
|
||||||
|
|
||||||
|
if (dev->d_lltype != NET_LL_ETHERNET)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_IPv4
|
||||||
|
#ifdef CONFIG_NET_IPv6
|
||||||
|
if (conn->domain == PF_INET)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
|
||||||
|
return (arp_find(conn->u.ipv4.raddr) != NULL);
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_IPv4 */
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_IPv6
|
||||||
|
#ifdef CONFIG_NET_IPv4
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR)
|
||||||
|
return (neighbor_findentry(conn->u.ipv6.raddr) != NULL);
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_IPv6 */
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_ETHERNET */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sendto_timeout
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Check for send timeout.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* pstate - sendto state structure
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* TRUE:timeout FALSE:no timeout
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* The network is locked
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_SOCKOPTS
|
||||||
|
static inline int sendto_timeout(FAR struct socket *psock,
|
||||||
|
FAR struct udp_conn_s *conn)
|
||||||
|
{
|
||||||
|
FAR struct udp_wrbuffer_s *wrb;
|
||||||
|
|
||||||
|
/* Peek at the head of the write queue (without altering the write queue). */
|
||||||
|
|
||||||
|
wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||||
|
if (wrb != NULL)
|
||||||
|
{
|
||||||
|
/* Check for a timeout configured via setsockopts(SO_SNDTIMEO).
|
||||||
|
* If none... we well let the send wait forever.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (psock->s_sndtimeo != 0)
|
||||||
|
{
|
||||||
|
/* Check if the configured timeout has elapsed */
|
||||||
|
|
||||||
|
return net_timeo(wrb->wb_start, psock->s_sndtimeo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No timeout */
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_SOCKOPTS */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sendto_next_transfer
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Setup for the next packet transfer
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* psock - Socket state structure
|
||||||
|
* conn - The UDP connection structure
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int sendto_next_transfer(FAR struct socket *psock,
|
||||||
|
FAR struct udp_conn_s *conn)
|
||||||
|
{
|
||||||
|
FAR struct udp_wrbuffer_s *wrb;
|
||||||
|
FAR struct net_driver_s *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Set the UDP "connection" to the destination address of the write buffer
|
||||||
|
* at the head of the queue.
|
||||||
|
*/
|
||||||
|
|
||||||
|
wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||||
|
DEBUGASSERT(wrb != NULL);
|
||||||
|
|
||||||
|
ret = udp_connect(conn, (FAR const struct sockaddr *)wrb->wb_iob->io_data);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
nerr("ERROR: udp_connect failed: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the device that will handle the remote packet transfers. This
|
||||||
|
* should never be NULL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dev = udp_find_raddr_device(conn);
|
||||||
|
if (dev == NULL)
|
||||||
|
{
|
||||||
|
nerr("ERROR: udp_find_raddr_device failed\n");
|
||||||
|
return -ENETUNREACH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is not the same device that we used in the last call to
|
||||||
|
* udp_callback_alloc(), then we need to release and reallocate the old
|
||||||
|
* callback instance.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (psock->s_sndcb != NULL && conn->dev != dev)
|
||||||
|
{
|
||||||
|
udp_callback_free(conn->dev, conn, psock->s_sndcb);
|
||||||
|
psock->s_sndcb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate resources to receive a callback from this device if the
|
||||||
|
* callback is not already in place.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (psock->s_sndcb == NULL)
|
||||||
|
{
|
||||||
|
psock->s_sndcb = udp_callback_alloc(dev, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test if the callback has been allocated */
|
||||||
|
|
||||||
|
if (psock->s_sndcb == NULL)
|
||||||
|
{
|
||||||
|
/* A buffer allocation error occurred */
|
||||||
|
|
||||||
|
nerr("ERROR: Failed to allocate callback\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->dev = dev;
|
||||||
|
|
||||||
|
/* Set up the callback in the connection */
|
||||||
|
|
||||||
|
psock->s_sndcb->flags = (UDP_POLL | NETDEV_DOWN);
|
||||||
|
psock->s_sndcb->priv = (FAR void *)psock;
|
||||||
|
psock->s_sndcb->event = sendto_eventhandler;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sendto_eventhandler
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is called to perform the actual send operation when
|
||||||
|
* polled by the lower, device interfacing layer.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* dev The structure of the network driver that caused the event
|
||||||
|
* conn The connection structure associated with the socket
|
||||||
|
* flags Set of events describing why the callback was invoked
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* The network is locked
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
|
||||||
|
FAR void *pvconn, FAR void *pvpriv,
|
||||||
|
uint16_t flags)
|
||||||
|
{
|
||||||
|
FAR struct udp_conn_s *conn = (FAR struct udp_conn_s *)pvconn;
|
||||||
|
FAR struct socket *psock = (FAR struct socket *)pvpriv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ninfo("flags: %04x\n", flags);
|
||||||
|
|
||||||
|
/* Check if the network device has gone down */
|
||||||
|
|
||||||
|
if ((flags & NETDEV_DOWN) != 0)
|
||||||
|
{
|
||||||
|
ninfo("Device down: %04x\n", flags);
|
||||||
|
|
||||||
|
/* Free write buffers and terminate polling */
|
||||||
|
|
||||||
|
sendto_netdev_down(psock, conn);
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for a normal polling cycle and if the outgoing packet is
|
||||||
|
* available. It would not be available if it has been claimed by a send
|
||||||
|
* event serving a different thread -OR- if the output buffer currently
|
||||||
|
* contains unprocessed incoming data. In these cases we will just have
|
||||||
|
* to wait for the next polling cycle.
|
||||||
|
*
|
||||||
|
* And, of course, we can do nothing if we have no data in the write
|
||||||
|
* buffers to send.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (dev->d_sndlen <= 0 && (flags & UDP_NEWDATA) != 0 &&
|
||||||
|
(flags & UDP_POLL) != 0 && !sq_empty(&conn->write_q))
|
||||||
|
{
|
||||||
|
/* Check if the destination IP address is in the ARP or Neighbor
|
||||||
|
* table. If not, then the send won't actually make it out... it
|
||||||
|
* will be replaced with an ARP request or Neighbor Solicitation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (sendto_addrcheck(conn, dev))
|
||||||
|
{
|
||||||
|
FAR struct udp_wrbuffer_s *wrb;
|
||||||
|
FAR struct udp_wrbuffer_s *tmp;
|
||||||
|
size_t sndlen;
|
||||||
|
|
||||||
|
/* Peek at the head of the write queue (but don't remove anything
|
||||||
|
* from the write queue yet). We know from the above test that
|
||||||
|
* the write_q is not empty.
|
||||||
|
*/
|
||||||
|
|
||||||
|
wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||||
|
DEBUGASSERT(wrb != NULL);
|
||||||
|
|
||||||
|
/* Get the amount of data that we can send in the next packet.
|
||||||
|
* We will send either the remaining data in the buffer I/O
|
||||||
|
* buffer chain, or as much as will fit given the MSS and current
|
||||||
|
* window size.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sndlen = wrb->wb_iob->io_pktlen;
|
||||||
|
ninfo("wrb=%p sndlen=%u\n", wrb, sndlen);
|
||||||
|
|
||||||
|
#ifdef NEED_IPDOMAIN_SUPPORT
|
||||||
|
/* If both IPv4 and IPv6 support are enabled, then we will need to
|
||||||
|
* select which one to use when generating the outgoing packet.
|
||||||
|
* If only one domain is selected, then the setup is already in
|
||||||
|
* place and we need do nothing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sendto_ipselect(dev, conn);
|
||||||
|
#endif
|
||||||
|
/* Then set-up to send that amount of data with the offset
|
||||||
|
* corresponding to the size of the IP-dependent address structure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
devif_iob_send(dev, wrb->wb_iob, sndlen, 0);
|
||||||
|
|
||||||
|
/* Remove and free the write buffer from the head of the write
|
||||||
|
* buffer queue.
|
||||||
|
*/
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
tmp = (FAR struct udp_wrbuffer_s *)sq_remfirst(&conn->write_q);
|
||||||
|
DEBUGASSERT(tmp == wrb);
|
||||||
|
|
||||||
|
udp_wrbuffer_release(tmp);
|
||||||
|
|
||||||
|
/* Check if the write queue became empty */
|
||||||
|
|
||||||
|
if (sq_empty(&conn->write_q))
|
||||||
|
{
|
||||||
|
/* Yes.. stifle any further callbacks until more write
|
||||||
|
* data is enqueued.
|
||||||
|
*/
|
||||||
|
|
||||||
|
psock->s_sndcb->flags = 0;
|
||||||
|
psock->s_sndcb->priv = NULL;
|
||||||
|
psock->s_sndcb->event = NULL;
|
||||||
|
ret = OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Set up for the next packet transfer by setting the
|
||||||
|
* connection address to the address of the next packet
|
||||||
|
* now at the header of of the write buffer queue.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = sendto_next_transfer(psock, conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (ret < 0);
|
||||||
|
|
||||||
|
/* Only one data can be sent by low level driver at once,
|
||||||
|
* tell the caller stop polling the other connections.
|
||||||
|
*/
|
||||||
|
|
||||||
|
flags &= ~UDP_POLL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_SOCKOPTS
|
||||||
|
/* We cannot send the data now. Check for a timeout. */
|
||||||
|
|
||||||
|
else if (sendto_timeout(psock, conn))
|
||||||
|
{
|
||||||
|
FAR struct udp_wrbuffer_s *wrb;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Remove and free the write buffer from the head of the write
|
||||||
|
* buffer queue. Here we know that the write queue is not empty
|
||||||
|
* because the entry at the head of the queue just timed out!
|
||||||
|
*/
|
||||||
|
|
||||||
|
wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&conn->write_q);
|
||||||
|
DEBUGASSERT(wrb != NULL);
|
||||||
|
|
||||||
|
udp_wrbuffer_release(wrb);
|
||||||
|
|
||||||
|
/* Set up for the next packet transfer by setting the connection
|
||||||
|
* address to the address of the next packet now at the header of the
|
||||||
|
* write buffer queue.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = sendto_next_transfer(psock, conn);
|
||||||
|
}
|
||||||
|
while (ret < 0);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_SOCKOPTS */
|
||||||
|
|
||||||
|
/* Continue waiting */
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sendto_txnotify
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Notify the appropriate device driver that we are have data ready to
|
||||||
|
* be send (UDP)
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* psock - Socket state structure
|
||||||
|
* conn - The UDP connection structure
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static inline void sendto_txnotify(FAR struct socket *psock,
|
||||||
|
FAR struct udp_conn_s *conn)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_NET_IPv4
|
||||||
|
#ifdef CONFIG_NET_IPv6
|
||||||
|
/* If both IPv4 and IPv6 support are enabled, then we will need to select
|
||||||
|
* the device driver using the appropriate IP domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (psock->s_domain == PF_INET)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* Notify the device driver that send data is available */
|
||||||
|
|
||||||
|
netdev_ipv4_txnotify(conn->u.ipv4.laddr, conn->u.ipv4.raddr);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_IPv4 */
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_IPv6
|
||||||
|
#ifdef CONFIG_NET_IPv4
|
||||||
|
else /* if (psock->s_domain == PF_INET6) */
|
||||||
|
#endif /* CONFIG_NET_IPv4 */
|
||||||
|
{
|
||||||
|
/* Notify the device driver that send data is available */
|
||||||
|
|
||||||
|
DEBUGASSERT(psock->s_domain == PF_INET6);
|
||||||
|
netdev_ipv6_txnotify(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_IPv6 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: psock_udp_sendto
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function implements the UDP-specific logic of the standard
|
||||||
|
* sendto() socket operation.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* psock A pointer to a NuttX-specific, internal socket structure
|
||||||
|
* buf Data to send
|
||||||
|
* len Length of data to send
|
||||||
|
* flags Send flags
|
||||||
|
* to Address of recipient
|
||||||
|
* tolen The length of the address structure
|
||||||
|
*
|
||||||
|
* NOTE: All input parameters were verified by sendto() before this
|
||||||
|
* function was called.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* On success, returns the number of characters sent. On error,
|
||||||
|
* a negated errno value is returned. See the description in
|
||||||
|
* net/socket/sendto.c for the list of appropriate return value.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
|
||||||
|
size_t len, int flags, FAR const struct sockaddr *to,
|
||||||
|
socklen_t tolen)
|
||||||
|
{
|
||||||
|
FAR struct udp_conn_s *conn;
|
||||||
|
FAR struct udp_wrbuffer_s *wrb;
|
||||||
|
int ret = OK;
|
||||||
|
|
||||||
|
/* Make sure that we have the IP address mapping */
|
||||||
|
|
||||||
|
conn = (FAR struct udp_conn_s *)psock->s_conn;
|
||||||
|
DEBUGASSERT(conn);
|
||||||
|
|
||||||
|
#if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
|
||||||
|
#ifdef CONFIG_NET_ARP_SEND
|
||||||
|
#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
|
||||||
|
if (psock->s_domain == PF_INET)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* Make sure that the IP address mapping is in the ARP table */
|
||||||
|
|
||||||
|
ret = arp_send(conn->u.ipv4.raddr);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_ARP_SEND */
|
||||||
|
|
||||||
|
#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
|
||||||
|
#ifdef CONFIG_NET_ARP_SEND
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* Make sure that the IP address mapping is in the Neighbor Table */
|
||||||
|
|
||||||
|
ret = icmpv6_neighbor(conn->u.ipv6.raddr);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_ICMPv6_NEIGHBOR */
|
||||||
|
|
||||||
|
/* Did we successfully get the address mapping? */
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
nerr("ERROR: Not reachable\n");
|
||||||
|
return -ENETUNREACH;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */
|
||||||
|
|
||||||
|
/* Dump the incoming buffer */
|
||||||
|
|
||||||
|
BUF_DUMP("psock_udp_send", buf, len);
|
||||||
|
|
||||||
|
/* Set the socket state to sending */
|
||||||
|
|
||||||
|
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
/* Allocate a write buffer. Careful, the network will be momentarily
|
||||||
|
* unlocked here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
net_lock();
|
||||||
|
wrb = udp_wrbuffer_alloc();
|
||||||
|
if (wrb == NULL)
|
||||||
|
{
|
||||||
|
/* A buffer allocation error occurred */
|
||||||
|
|
||||||
|
nerr("ERROR: Failed to allocate write buffer\n");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto errout_with_lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the write buffer */
|
||||||
|
|
||||||
|
memcpy(&wrb->wb_dest, to, tolen);
|
||||||
|
wrb->wb_start = clock_systimer();
|
||||||
|
|
||||||
|
/* Copy the user data into the write buffer. We cannot wait for
|
||||||
|
* buffer space if the socket was opened non-blocking.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (_SS_ISNONBLOCK(psock->s_flags))
|
||||||
|
{
|
||||||
|
ret = iob_trycopyin(wrb->wb_iob, (FAR uint8_t *)buf, len, 0, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = iob_copyin(wrb->wb_iob, (FAR uint8_t *)buf, len, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
goto errout_with_wrb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dump I/O buffer chain */
|
||||||
|
|
||||||
|
UDPWB_DUMP("I/O buffer chain", wrb, wrb->wb_iob->io_pktlen, 0);
|
||||||
|
|
||||||
|
/* sendto_eventhandler() will send data in FIFO order from the
|
||||||
|
* conn->write_q
|
||||||
|
*/
|
||||||
|
|
||||||
|
sq_addlast(&wrb->wb_node, &conn->write_q);
|
||||||
|
ninfo("Queued WRB=%p pktlen=%u write_q(%p,%p)\n",
|
||||||
|
wrb, wrb->wb_iob->io_pktlen,
|
||||||
|
conn->write_q.head, conn->write_q.tail);
|
||||||
|
|
||||||
|
/* Set up for the next packet transfer by setting the connection
|
||||||
|
* address to the address of the next packet now at the header of the
|
||||||
|
* write buffer queue.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = sendto_next_transfer(psock, conn);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
/* REVISIT: An error here is not recoverable */
|
||||||
|
|
||||||
|
goto errout_with_lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify the device driver of the availability of TX data */
|
||||||
|
|
||||||
|
sendto_txnotify(psock, conn);
|
||||||
|
net_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the socket state to idle */
|
||||||
|
|
||||||
|
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
|
||||||
|
|
||||||
|
/* Return the number of bytes that will be sent */
|
||||||
|
|
||||||
|
return len;
|
||||||
|
|
||||||
|
errout_with_wrb:
|
||||||
|
udp_wrbuffer_release(wrb);
|
||||||
|
|
||||||
|
errout_with_lock:
|
||||||
|
net_unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_NET && CONFIG_NET_UDP && CONFIG_NET_UDP_WRITE_BUFFERS */
|
@ -1,7 +1,8 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* net/udp/udp_psock_sendto.c
|
* net/udp/udp_psock_sendto_unbuffered.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007-2009, 2011-2016 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007-2009, 2011-2016, 2018 Gregory Nutt. All rights
|
||||||
|
* reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -94,7 +95,7 @@ struct sendto_s
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: send_timeout
|
* Name: sendto_timeout
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Check for send timeout.
|
* Check for send timeout.
|
||||||
@ -111,7 +112,7 @@ struct sendto_s
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_NET_SOCKOPTS
|
#ifdef CONFIG_NET_SOCKOPTS
|
||||||
static inline int send_timeout(FAR struct sendto_s *pstate)
|
static inline int sendto_timeout(FAR struct sendto_s *pstate)
|
||||||
{
|
{
|
||||||
FAR struct socket *psock;
|
FAR struct socket *psock;
|
||||||
|
|
||||||
@ -235,7 +236,7 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_NET_SOCKOPTS
|
#ifdef CONFIG_NET_SOCKOPTS
|
||||||
if (send_timeout(pstate))
|
if (sendto_timeout(pstate))
|
||||||
{
|
{
|
||||||
/* Yes.. report the timeout */
|
/* Yes.. report the timeout */
|
||||||
|
|
217
net/udp/udp_wrbuffer.c
Normal file
217
net/udp/udp_wrbuffer.c
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* net/udp/udp_wrbuffer.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/net/netconfig.h>
|
||||||
|
#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP) && defined(CONFIG_NET_UDP_WRITE_BUFFERS)
|
||||||
|
|
||||||
|
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_NET_UDP_WRBUFFER_DEBUG)
|
||||||
|
/* Force debug output (from this file only) */
|
||||||
|
|
||||||
|
# undef CONFIG_DEBUG_NET
|
||||||
|
# define CONFIG_DEBUG_NET 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <queue.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/semaphore.h>
|
||||||
|
#include <nuttx/net/net.h>
|
||||||
|
#include <nuttx/mm/iob.h>
|
||||||
|
|
||||||
|
#include "udp/udp.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Package all globals used by this logic into a structure */
|
||||||
|
|
||||||
|
struct wrbuffer_s
|
||||||
|
{
|
||||||
|
/* The semaphore to protect the buffers */
|
||||||
|
|
||||||
|
sem_t sem;
|
||||||
|
|
||||||
|
/* This is the list of available write buffers */
|
||||||
|
|
||||||
|
sq_queue_t freebuffers;
|
||||||
|
|
||||||
|
/* These are the pre-allocated write buffers */
|
||||||
|
|
||||||
|
struct udp_wrbuffer_s buffers[CONFIG_NET_UDP_NWRBCHAINS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* This is the state of the global write buffer resource */
|
||||||
|
|
||||||
|
static struct wrbuffer_s g_wrbuffer;
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: udp_wrbuffer_initialize
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Initialize the list of free write buffers
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* Called once early initialization.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void udp_wrbuffer_initialize(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sq_init(&g_wrbuffer.freebuffers);
|
||||||
|
|
||||||
|
for (i = 0; i < CONFIG_NET_UDP_NWRBCHAINS; i++)
|
||||||
|
{
|
||||||
|
sq_addfirst(&g_wrbuffer.buffers[i].wb_node, &g_wrbuffer.freebuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
nxsem_init(&g_wrbuffer.sem, 0, CONFIG_NET_UDP_NWRBCHAINS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: udp_wrbuffer_alloc
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Allocate a UDP write buffer by taking a pre-allocated buffer from
|
||||||
|
* the free list. This function is called from UDP logic when a buffer
|
||||||
|
* of UDP data is about to sent
|
||||||
|
*
|
||||||
|
* Input parameters:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* Called from user logic with the network locked.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void)
|
||||||
|
{
|
||||||
|
FAR struct udp_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
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGVERIFY(net_lockedwait(&g_wrbuffer.sem)); /* TODO: Handle EINTR. */
|
||||||
|
|
||||||
|
/* Now, we are guaranteed to have a write buffer structure reserved
|
||||||
|
* for us in the free list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers);
|
||||||
|
DEBUGASSERT(wrb);
|
||||||
|
memset(wrb, 0, sizeof(struct udp_wrbuffer_s));
|
||||||
|
|
||||||
|
/* Now get the first I/O buffer for the write buffer structure */
|
||||||
|
|
||||||
|
wrb->wb_iob = iob_alloc(false);
|
||||||
|
if (!wrb->wb_iob)
|
||||||
|
{
|
||||||
|
nerr("ERROR: Failed to allocate I/O buffer\n");
|
||||||
|
udp_wrbuffer_release(wrb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: udp_wrbuffer_release
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Release a UDP write buffer by returning the buffer to the free list.
|
||||||
|
* This function is called from user logic after it is consumed the
|
||||||
|
* buffered data.
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* This function must be called with the network locked.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void udp_wrbuffer_release(FAR struct udp_wrbuffer_s *wrb)
|
||||||
|
{
|
||||||
|
DEBUGASSERT(wrb && wrb->wb_iob);
|
||||||
|
|
||||||
|
/* To avoid deadlocks, we must following this ordering: Release the I/O
|
||||||
|
* buffer chain first, then the write buffer structure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
iob_free_chain(wrb->wb_iob);
|
||||||
|
|
||||||
|
/* Then free the write buffer structure */
|
||||||
|
|
||||||
|
sq_addlast(&wrb->wb_node, &g_wrbuffer.freebuffers);
|
||||||
|
nxsem_post(&g_wrbuffer.sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: udp_wrbuffer_test
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Check if there is room in the write buffer. Does not reserve any space.
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int udp_wrbuffer_test(void)
|
||||||
|
{
|
||||||
|
int val = 0;
|
||||||
|
nxsem_getvalue(&g_wrbuffer.sem, &val);
|
||||||
|
return val > 0 ? OK : ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_NET && CONFIG_NET_UDP && CONFIG_NET_UDP_WRITE_BUFFERS */
|
70
net/udp/udp_wrbuffer_dump.c
Normal file
70
net/udp/udp_wrbuffer_dump.c
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* net/udp/udp_wrbuffer_dump.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/mm/iob.h>
|
||||||
|
|
||||||
|
#include "udp/udp.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FEATURES
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: udp_wrbuffer_dump
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Dump the contents of a write buffer
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void udp_wrbuffer_dump(FAR const char *msg, FAR struct udp_wrbuffer_s *wrb,
|
||||||
|
unsigned int len, unsigned int offset)
|
||||||
|
{
|
||||||
|
syslog(LOG_DEBUG, "%s: wrb=%p pktlen=%d\n", msg, wrb, wrb->wb_iob->io_pktlen);
|
||||||
|
iob_dump("I/O Buffer Chain", wrb->wb_iob, len, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_DEBUG_FEATURES */
|
Loading…
Reference in New Issue
Block a user