mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2026-08-10 01:23:48 +08:00
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:
169
src/core/tcp.c
169
src/core/tcp.c
@@ -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 */
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user