Bugfix: there was a problem with TCP segments not being properly retransmitted for protosockets-based applications. Cleaning up the logic around acknowledgements and retransmissions fixed the bugs pertaining to retransmissions of lost packets. This bugfix affects both the telnet server and the web server (which now work as expected wrt packet loss).

This commit is contained in:
adamdunkels 2008-10-31 18:10:24 +00:00
parent 7b87c2f5dc
commit d73124cc5e

View file

@ -30,7 +30,7 @@
*
* Author: Adam Dunkels <adam@sics.se>
*
* $Id: psock.c,v 1.5 2007/11/17 18:05:21 adamdunkels Exp $
* $Id: psock.c,v 1.6 2008/10/31 18:10:24 adamdunkels Exp $
*/
#include <stdio.h>
@ -140,8 +140,11 @@ buf_bufto(CC_REGISTER_ARG struct psock_buf *buf, u8_t endmarker,
}
/*---------------------------------------------------------------------------*/
static char
send_data(CC_REGISTER_ARG struct psock *s)
data_is_sent_and_acked(CC_REGISTER_ARG struct psock *s)
{
/* If data has previously been sent, and the data has been acked, we
increase the send pointer and call send_data() to send more
data. */
if(s->state != STATE_DATA_SENT || uip_rexmit()) {
if(s->sendlen > uip_mss()) {
uip_send(s->sendptr, uip_mss());
@ -149,15 +152,8 @@ send_data(CC_REGISTER_ARG struct psock *s)
uip_send(s->sendptr, s->sendlen);
}
s->state = STATE_DATA_SENT;
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
static char
data_acked(CC_REGISTER_ARG struct psock *s)
{
if(s->state == STATE_DATA_SENT && uip_acked()) {
return 0;
} else if(s->state == STATE_DATA_SENT && uip_acked()) {
if(s->sendlen > uip_mss()) {
s->sendlen -= uip_mss();
s->sendptr += uip_mss();
@ -193,16 +189,11 @@ PT_THREAD(psock_send(CC_REGISTER_ARG struct psock *s, const uint8_t *buf,
while(s->sendlen > 0) {
/*
* The condition for this PT_WAIT_UNTIL is a little tricky: the
* protothread will wait here until all data has been acknowledged
* (data_acked() returns true) and until all data has been sent
* (send_data() returns true). The two functions data_acked() and
* send_data() must be called in succession to ensure that all
* data is sent. Therefore the & operator is used instead of the
* && operator, which would cause only the data_acked() function
* to be called when it returns false.
* The protothread will wait here until all data has been
* acknowledged and sent (data_is_acked_and_send() returns 1).
*/
PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
PT_YIELD_UNTIL(&s->psockpt, data_is_sent_and_acked(s));
printf("sendlen %d\n", s->sendlen);
}
s->state = STATE_NONE;
@ -220,21 +211,23 @@ PT_THREAD(psock_generator_send(CC_REGISTER_ARG struct psock *s,
PT_EXIT(&s->psockpt);
}
/* Call the generator function to generate the data in the
uip_appdata buffer. */
s->sendlen = generate(arg);
s->sendptr = uip_appdata;
s->state = STATE_NONE;
s->state = STATE_NONE;
do {
/* Call the generator function again if we are called to perform a
retransmission. */
if(uip_rexmit()) {
generate(arg);
/* Call the generator function to generate the data in the
uip_appdata buffer. */
s->sendlen = generate(arg);
s->sendptr = uip_appdata;
if(s->sendlen > uip_mss()) {
uip_send(s->sendptr, uip_mss());
} else {
uip_send(s->sendptr, s->sendlen);
}
s->state = STATE_DATA_SENT;
/* Wait until all data is sent and acknowledged. */
PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
} while(s->sendlen > 0);
PT_YIELD_UNTIL(&s->psockpt, uip_acked() || uip_rexmit());
} while(!uip_acked());
s->state = STATE_NONE;