Fixed some issues in the TCP_OVERSIZE code:

- reset tcp_pcb.unsent_oversize when last_unsent is changed;
- added TCP_OVERSIZE_DBGCHECK: check tcp_pcb.unsent_oversize vs. (debug-only) tcp_seg.oversize_left to ensure the pcb counter is correct;
- fixed a memory leak in tcp_write;
This commit is contained in:
goldsimon 2010-03-12 15:40:01 +00:00
parent 90c7d3aaff
commit 097e8c8eb4
3 changed files with 43 additions and 1 deletions

View File

@ -1344,6 +1344,9 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
tcp_segs_free(pcb->unsent); tcp_segs_free(pcb->unsent);
tcp_segs_free(pcb->unacked); tcp_segs_free(pcb->unacked);
pcb->unacked = pcb->unsent = NULL; pcb->unacked = pcb->unsent = NULL;
#if TCP_OVERSIZE
pcb->unsent_oversize = 0;
#endif /* TCP_OVERSIZE */
} }
} }

View File

@ -147,6 +147,9 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
seg->p = p; seg->p = p;
seg->dataptr = p->payload; seg->dataptr = p->payload;
seg->len = p->tot_len - optlen; seg->len = p->tot_len - optlen;
#if TCP_OVERSIZE_DBGCHECK
seg->oversize_left = 0;
#endif /* TCP_OVERSIZE_DBGCHECK */
/* build TCP header */ /* build TCP header */
if (pbuf_header(p, TCP_HLEN)) { if (pbuf_header(p, TCP_HLEN)) {
@ -355,11 +358,16 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
* function. * function.
*/ */
#if TCP_OVERSIZE #if TCP_OVERSIZE
#if TCP_OVERSIZE_DBGCHECK
/* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */
LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)",
pcb->unsent_oversize == last_unsent->oversize_left);
#endif /* TCP_OVERSIZE_DBGCHECK */
oversize = pcb->unsent_oversize; oversize = pcb->unsent_oversize;
if (oversize > 0) { if (oversize > 0) {
LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space);
seg = last_unsent; seg = last_unsent;
oversize_used = oversize < len ? oversize : len; oversize_used = oversize < len ? oversize : len;
LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space);
pos += oversize_used; pos += oversize_used;
oversize -= oversize_used; oversize -= oversize_used;
space -= oversize_used; space -= oversize_used;
@ -390,6 +398,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
seglen)); seglen));
goto memerr; goto memerr;
} }
#if TCP_OVERSIZE_DBGCHECK
last_unsent->oversize_left = oversize;
#endif /* TCP_OVERSIZE_DBGCHECK */
MEMCPY(concat_p->payload, (u8_t*)arg + pos, seglen); MEMCPY(concat_p->payload, (u8_t*)arg + pos, seglen);
} else { } else {
/* Data is not copied */ /* Data is not copied */
@ -404,6 +415,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
pos += seglen; pos += seglen;
queuelen += pbuf_clen(concat_p); queuelen += pbuf_clen(concat_p);
} }
} else {
LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)",
pcb->unsent_oversize == 0);
} }
/* /*
@ -435,6 +449,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
* party) we can safely use PBUF_ROM instead of PBUF_REF here. * party) we can safely use PBUF_ROM instead of PBUF_REF here.
*/ */
struct pbuf *p2; struct pbuf *p2;
LWIP_ASSERT("oversize == 0", oversize == 0);
if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n")); LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
goto memerr; goto memerr;
@ -461,12 +476,16 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
* overflows. */ * overflows. */
if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
pbuf_free(p);
goto memerr; goto memerr;
} }
if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) {
goto memerr; goto memerr;
} }
#if TCP_OVERSIZE_DBGCHECK
seg->oversize_left = oversize;
#endif /* TCP_OVERSIZE_DBGCHECK */
/* Fix dataptr for the nocopy case */ /* Fix dataptr for the nocopy case */
if ((apiflags & TCP_WRITE_FLAG_COPY) == 0) { if ((apiflags & TCP_WRITE_FLAG_COPY) == 0) {
seg->dataptr = (u8_t*)arg + pos; seg->dataptr = (u8_t*)arg + pos;
@ -511,6 +530,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
} }
} }
last_unsent->len += oversize_used; last_unsent->len += oversize_used;
#if TCP_OVERSIZE_DBGCHECK
last_unsent->oversize_left -= oversize_used;
#endif /* TCP_OVERSIZE_DBGCHECK */
} }
pcb->unsent_oversize = oversize; pcb->unsent_oversize = oversize;
#endif /* TCP_OVERSIZE */ #endif /* TCP_OVERSIZE */
@ -889,6 +911,12 @@ tcp_output(struct tcp_pcb *pcb)
} }
seg = pcb->unsent; seg = pcb->unsent;
} }
#if TCP_OVERSIZE
if (pcb->unsent == NULL) {
/* last unsent has been removed, reset unsent_oversize */
pcb->unsent_oversize = 0;
}
#endif /* TCP_OVERSIZE */
if (seg != NULL && pcb->persist_backoff == 0 && if (seg != NULL && pcb->persist_backoff == 0 &&
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) { ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {

View File

@ -253,12 +253,23 @@ PACK_STRUCT_END
#endif /* LWIP_EVENT_API */ #endif /* LWIP_EVENT_API */
#if TCP_OVERSIZE && defined(LWIP_DEBUG)
#define TCP_OVERSIZE_DBGCHECK 1
#else
#define TCP_OVERSIZE_DBGCHECK 0
#endif
/* This structure represents a TCP segment on the unsent and unacked queues */ /* This structure represents a TCP segment on the unsent and unacked queues */
struct tcp_seg { struct tcp_seg {
struct tcp_seg *next; /* used when putting segements on a queue */ struct tcp_seg *next; /* used when putting segements on a queue */
struct pbuf *p; /* buffer containing data + TCP header */ struct pbuf *p; /* buffer containing data + TCP header */
void *dataptr; /* pointer to the TCP data in the pbuf */ void *dataptr; /* pointer to the TCP data in the pbuf */
u16_t len; /* the TCP length of this segment */ u16_t len; /* the TCP length of this segment */
#if TCP_OVERSIZE_DBGCHECK
u16_t oversize_left; /* Extra bytes available at the end of the last
pbuf in unsent (used for asserting vs.
tcp_pcb.unsent_oversized only) */
#endif /* TCP_OVERSIZE_DBGCHECK */
u8_t flags; u8_t flags;
#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ #define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */
#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ #define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */