tcp: introduce ext_args per pcb

This introduces the concept of ext (external/extended) arguments per
tcp_pcb (also for listening pcbs) to store more data than just one
"void *arg" per pcb. The "arg" is for use to applications, whereas
the ext_args may be used by frameworks and leave "arg" untouched.

In addition to a void pointer, callbacks are added to help frameworks
migrate arguments from listen pcb to connection pcb and to free args
when the pcb is freed.

Signed-off-by: goldsimon <goldsimon@gmx.de>
This commit is contained in:
goldsimon 2018-01-24 22:01:39 +01:00
parent ebe782ba16
commit 0e85582bc0
6 changed files with 238 additions and 2 deletions

View File

@ -2136,7 +2136,8 @@ PREDEFINED = __DOXYGEN__=1 \
SO_REUSE=1 \
SO_REUSE_RXTOALL=1 \
LWIP_HAVE_SLIPIF=1 \
LWIP_6LOWPAN=1
LWIP_6LOWPAN=1 \
LWIP_TCP_PCB_NUM_EXT_ARGS=1
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The

View File

@ -8,7 +8,7 @@
* Transmission Control Protocol for IP\n
* @see @ref api
*
* Common functions for the TCP implementation, such as functinos
* Common functions for the TCP implementation, such as functions
* for manipulating the data structures and the TCP timer functions. TCP functions
* related to input and output is found in tcp_in.c and tcp_out.c respectively.\n
*
@ -190,6 +190,9 @@ static u8_t tcp_timer_ctr;
static u16_t tcp_new_port(void);
static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb);
#if LWIP_TCP_PCB_NUM_EXT_ARGS
static void tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args);
#endif
/**
* Initialize this module.
@ -207,6 +210,9 @@ void
tcp_free(struct tcp_pcb *pcb)
{
LWIP_ASSERT("tcp_free: LISTEN", pcb->state != LISTEN);
#if LWIP_TCP_PCB_NUM_EXT_ARGS
tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args);
#endif
memp_free(MEMP_TCP_PCB, pcb);
}
@ -215,6 +221,9 @@ static void
tcp_free_listen(struct tcp_pcb *pcb)
{
LWIP_ASSERT("tcp_free_listen: !LISTEN", pcb->state != LISTEN);
#if LWIP_TCP_PCB_NUM_EXT_ARGS
tcp_ext_arg_invoke_callbacks_destroyed(pcb->ext_args);
#endif
memp_free(MEMP_TCP_PCB_LISTEN, pcb);
}
@ -866,6 +875,10 @@ tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err)
if (pcb->local_port != 0) {
TCP_RMV(&tcp_bound_pcbs, pcb);
}
#if LWIP_TCP_PCB_NUM_EXT_ARGS
/* copy over ext_args to listening pcb */
memcpy(&lpcb->ext_args, &pcb->ext_args, sizeof(pcb->ext_args));
#endif
tcp_free(pcb);
#if LWIP_CALLBACK_API
lpcb->accept = tcp_accept_null;
@ -2460,4 +2473,158 @@ tcp_pcbs_sane(void)
}
#endif /* TCP_DEBUG */
#if LWIP_TCP_PCB_NUM_EXT_ARGS
/**
* @defgroup tcp_raw_extargs ext arguments
* @ingroup tcp_raw
* Additional data storage per tcp pcb\n
* @see @ref tcp_raw
*
* When LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb)
* includes a number of additional argument entries in an array.
*
* To support memory management, in addition to a 'void *', callbacks can be
* provided to manage transition from listening pcbs to connections and to
* deallocate memory when a pcb is deallocated (see struct @ref tcp_ext_arg_callbacks).
*
* After allocating this index, use @ref tcp_ext_arg_set and @ref tcp_ext_arg_get
* to store and load arguments from this index for a given pcb.
*/
static u8_t tcp_ext_arg_id;
/**
* @ingroup tcp_raw_extargs
* Allocate an index to store data in ext_args member of struct tcp_pcb.
* Returned value is an index in mentioned array.
* The index is *global* over all pcbs!
*
* When @ref LWIP_TCP_PCB_NUM_EXT_ARGS is > 0, every tcp pcb (including listen pcb)
* includes a number of additional argument entries in an array.
*
* To support memory management, in addition to a 'void *', callbacks can be
* provided to manage transition from listening pcbs to connections and to
* deallocate memory when a pcb is deallocated (see struct @ref tcp_ext_arg_callbacks).
*
* After allocating this index, use @ref tcp_ext_arg_set and @ref tcp_ext_arg_get
* to store and load arguments from this index for a given pcb.
*
* @return a unique index into struct tcp_pcb.ext_args
*/
u8_t
tcp_ext_arg_alloc_id(void)
{
u8_t result = tcp_ext_arg_id;
tcp_ext_arg_id++;
LWIP_ASSERT_CORE_LOCKED();
#if LWIP_TCP_PCB_NUM_EXT_ARGS >= 255
#error LWIP_TCP_PCB_NUM_EXT_ARGS
#endif
LWIP_ASSERT("Increase LWIP_TCP_PCB_NUM_EXT_ARGS in lwipopts.h", result < LWIP_TCP_PCB_NUM_EXT_ARGS);
return result;
}
/**
* @ingroup tcp_raw_extargs
* Set callbacks for a given index of ext_args on the specified pcb.
*
* @param pcb tcp_pcb for which to set the callback
* @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id)
* @param callbacks callback table (const since it is referenced, not copied!)
*/
void
tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks)
{
LWIP_ASSERT("pcb != NULL", pcb != NULL);
LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS);
LWIP_ASSERT("callbacks != NULL", callbacks != NULL);
LWIP_ASSERT_CORE_LOCKED();
pcb->ext_args[id].callbacks = callbacks;
}
/**
* @ingroup tcp_raw_extargs
* Set data for a given index of ext_args on the specified pcb.
*
* @param pcb tcp_pcb for which to set the data
* @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id)
* @param arg data pointer to set
*/
void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg)
{
LWIP_ASSERT("pcb != NULL", pcb != NULL);
LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS);
LWIP_ASSERT_CORE_LOCKED();
pcb->ext_args[id].data = arg;
}
/**
* @ingroup tcp_raw_extargs
* Set data for a given index of ext_args on the specified pcb.
*
* @param pcb tcp_pcb for which to set the data
* @param id ext_args index to set (allocated via @ref tcp_ext_arg_alloc_id)
* @return data pointer at the given index
*/
void *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id)
{
LWIP_ASSERT("pcb != NULL", pcb != NULL);
LWIP_ASSERT("id < LWIP_TCP_PCB_NUM_EXT_ARGS", id < LWIP_TCP_PCB_NUM_EXT_ARGS);
LWIP_ASSERT_CORE_LOCKED();
return pcb->ext_args[id].data;
}
/** This function calls the "destroy" callback for all ext_args once a pcb is
* freed.
*/
static void
tcp_ext_arg_invoke_callbacks_destroyed(struct tcp_pcb_ext_args *ext_args)
{
int i;
LWIP_ASSERT("ext_args != NULL", ext_args != NULL);
for (i = 0; i < LWIP_TCP_PCB_NUM_EXT_ARGS; i++) {
if (ext_args[i].callbacks != NULL) {
if (ext_args[i].callbacks->destroy != NULL) {
ext_args[i].callbacks->destroy((u8_t)i, ext_args[i].data);
}
}
}
}
/** This function calls the "passive_open" callback for all ext_args if a connection
* is in the process of being accepted. This is called just after the SYN is
* received and before a SYN/ACK is sent, to allow to modify the very first
* segment sent even on passive open. Naturally, the "accepted" callback of the
* pcb has not been called yet!
*/
err_t
tcp_ext_arg_invoke_callbacks_passive_open(struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb)
{
int i;
LWIP_ASSERT("lpcb != NULL", lpcb != NULL);
LWIP_ASSERT("cpcb != NULL", cpcb != NULL);
for (i = 0; i < LWIP_TCP_PCB_NUM_EXT_ARGS; i++) {
if (lpcb->ext_args[i].callbacks != NULL) {
if (lpcb->ext_args[i].callbacks->passive_open != NULL) {
err_t err = lpcb->ext_args[i].callbacks->passive_open((u8_t)i, lpcb, cpcb);
if (err != ERR_OK) {
return err;
}
}
}
}
return ERR_OK;
}
#endif /* LWIP_TCP_PCB_NUM_EXT_ARGS */
#endif /* LWIP_TCP */

View File

@ -680,6 +680,13 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
MIB2_STATS_INC(mib2.tcppassiveopens);
#if LWIP_TCP_PCB_NUM_EXT_ARGS
if (tcp_ext_arg_invoke_callbacks_passive_open(pcb, npcb) != ERR_OK) {
tcp_abandon(npcb, 0);
return;
}
#endif
/* Send a SYN|ACK together with the MSS option. */
rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
if (rc != ERR_OK) {

View File

@ -1465,6 +1465,15 @@
#define TCP_RCV_SCALE 0
#endif
/**
* LWIP_TCP_PCB_NUM_EXT_ARGS:
* When this is > 0, every tcp pcb (including listen pcb) includes a number of
* additional argument entries in an array (see tcp_ext_arg_alloc_id)
*/
#if !defined LWIP_TCP_PCB_NUM_EXT_ARGS || defined __DOXYGEN__
#define LWIP_TCP_PCB_NUM_EXT_ARGS 0
#endif
/** LWIP_ALTCP==1: enable the altcp API
* altcp is an abstraction layer that prevents applications linking against the
* tcp.h functions but provides the same functionality. It is used to e.g. add

View File

@ -508,6 +508,10 @@ void tcp_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_a
void tcp_free_ooseq(struct tcp_pcb *pcb);
#endif
#if LWIP_TCP_PCB_NUM_EXT_ARGS
err_t tcp_ext_arg_invoke_callbacks_passive_open(struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -56,6 +56,7 @@ extern "C" {
#endif
struct tcp_pcb;
struct tcp_pcb_listen;
/** Function prototype for tcp accept callback functions. Called when a new
* connection can be accepted on a listening pcb.
@ -163,6 +164,45 @@ struct tcp_sack_range {
};
#endif /* LWIP_TCP_SACK_OUT */
/** Function prototype for deallocation of arguments. Called *just before* the
* pcb is freed, so don't expect to be able to do anything with this pcb!
*
* @param id ext arg id (allocated via @ref tcp_ext_arg_alloc_id)
* @param data pointer to the data (set via @ref tcp_ext_arg_set before)
*/
typedef void (*tcp_extarg_callback_pcb_destroyed_fn)(u8_t id, void *data);
/** Function prototype to transition arguments from a listening pcb to an accepted pcb
*
* @param id ext arg id (allocated via @ref tcp_ext_arg_alloc_id)
* @param lpcb the listening pcb accepting a connection
* @param cpcb the newly allocated connection pcb
* @param ERR_OK if OK, any error if connection should be dropped
*/
typedef err_t (*tcp_extarg_callback_passive_open_fn)(u8_t id, struct tcp_pcb_listen *lpcb, struct tcp_pcb *cpcb);
/** A table of callback functions that is invoked for ext arguments */
struct tcp_ext_arg_callbacks {
/** @ref tcp_extarg_callback_pcb_destroyed_fn */
tcp_extarg_callback_pcb_destroyed_fn destroy;
/** @ref tcp_extarg_callback_passive_open_fn */
tcp_extarg_callback_passive_open_fn passive_open;
};
#define LWIP_TCP_PCB_NUM_EXT_ARG_ID_INVALID 0xFF
#if LWIP_TCP_PCB_NUM_EXT_ARGS
/* This is the structure for ext args in tcp pcbs (used as array) */
struct tcp_pcb_ext_args {
const struct tcp_ext_arg_callbacks *callbacks;
void *data;
};
/* This is a helper define to prevent zero size arrays if disabled */
#define TCP_PCB_EXTARGS struct tcp_pcb_ext_args ext_args[LWIP_TCP_PCB_NUM_EXT_ARGS];
#else
#define TCP_PCB_EXTARGS
#endif
typedef u16_t tcpflags_t;
/**
@ -171,6 +211,7 @@ typedef u16_t tcpflags_t;
#define TCP_PCB_COMMON(type) \
type *next; /* for the linked list */ \
void *callback_arg; \
TCP_PCB_EXTARGS \
enum tcp_state state; /* TCP state */ \
u8_t prio; \
/* ports are in host byte order */ \
@ -442,6 +483,13 @@ err_t tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_add
/* for compatibility with older implementation */
#define tcp_new_ip6() tcp_new_ip_type(IPADDR_TYPE_V6)
#if LWIP_TCP_PCB_NUM_EXT_ARGS
u8_t tcp_ext_arg_alloc_id(void);
void tcp_ext_arg_set_callbacks(struct tcp_pcb *pcb, uint8_t id, const struct tcp_ext_arg_callbacks * const callbacks);
void tcp_ext_arg_set(struct tcp_pcb *pcb, uint8_t id, void *arg);
void *tcp_ext_arg_get(const struct tcp_pcb *pcb, uint8_t id);
#endif
#ifdef __cplusplus
}
#endif