Skip to content

Commit 5071cee

Browse files
committed
extmod/modlwip: Store a chain of incoming pbufs, instead of only one.
Storing a chain of pbuf was an original design of @pfalcon's lwIP socket module. The problem with storing just one, like modlwip does is that "peer closed connection" notification is completely asynchronous and out of band. So, there may be following sequence of actions: 1. pbuf adafruit#1 arrives, and stored in a socket. 2. pbuf adafruit#2 arrives, and rejected, which causes lwIP to put it into a queue to re-deliver later. 3. "Peer closed connection" is signaled, and socket is set at such status. 4. pbuf adafruit#1 is processed. 5. There's no stored pbufs in teh socket, and socket status is "peer closed connection", so EOF is returned to a client. 6. pbuf adafruit#2 gets redelivered. Apparently, there's no easy workaround for this, except to queue all incoming pbufs in a socket. This may lead to increased memory pressure, as number of pending packets would be regulated only by TCP/IP flow control, whereas with previous setup lwIP had a global overlook of number packets waiting for redelivery and could regulate them centrally.
1 parent c7fba52 commit 5071cee

1 file changed

Lines changed: 31 additions & 19 deletions

File tree

extmod/modlwip.c

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ typedef struct _lwip_socket_obj_t {
239239
byte peer[4];
240240
mp_uint_t peer_port;
241241
mp_uint_t timeout;
242-
uint16_t leftover_count;
242+
uint16_t recv_offset;
243243

244244
uint8_t domain;
245245
uint8_t type;
@@ -354,11 +354,17 @@ STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err
354354
socket->state = STATE_PEER_CLOSED;
355355
exec_user_callback(socket);
356356
return ERR_OK;
357-
} else if (socket->incoming.pbuf != NULL) {
358-
// No room in the inn, let LWIP know it's still responsible for delivery later
357+
}
358+
359+
if (socket->incoming.pbuf == NULL) {
360+
socket->incoming.pbuf = p;
361+
} else {
362+
#ifdef SOCKET_SINGLE_PBUF
359363
return ERR_BUF;
364+
#else
365+
pbuf_cat(socket->incoming.pbuf, p);
366+
#endif
360367
}
361-
socket->incoming.pbuf = p;
362368

363369
exec_user_callback(socket);
364370

@@ -536,22 +542,28 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
536542

537543
struct pbuf *p = socket->incoming.pbuf;
538544

539-
if (socket->leftover_count == 0) {
540-
socket->leftover_count = p->tot_len;
545+
mp_uint_t remaining = p->len - socket->recv_offset;
546+
if (len > remaining) {
547+
len = remaining;
541548
}
542549

543-
u16_t result = pbuf_copy_partial(p, buf, ((socket->leftover_count >= len) ? len : socket->leftover_count), (p->tot_len - socket->leftover_count));
544-
if (socket->leftover_count > len) {
545-
// More left over...
546-
socket->leftover_count -= len;
547-
} else {
550+
memcpy(buf, (byte*)p->payload + socket->recv_offset, len);
551+
552+
remaining -= len;
553+
if (remaining == 0) {
554+
socket->incoming.pbuf = p->next;
555+
// If we don't ref here, free() will free the entire chain,
556+
// if we ref, it does what we need: frees 1st buf, and decrements
557+
// next buf's refcount back to 1.
558+
pbuf_ref(p->next);
548559
pbuf_free(p);
549-
socket->incoming.pbuf = NULL;
550-
socket->leftover_count = 0;
560+
socket->recv_offset = 0;
561+
} else {
562+
socket->recv_offset += len;
551563
}
564+
tcp_recved(socket->pcb.tcp, len);
552565

553-
tcp_recved(socket->pcb.tcp, result);
554-
return (mp_uint_t) result;
566+
return len;
555567
}
556568

557569
/*******************************************************************************/
@@ -561,8 +573,8 @@ STATIC const mp_obj_type_t lwip_socket_type;
561573

562574
STATIC void lwip_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
563575
lwip_socket_obj_t *self = self_in;
564-
mp_printf(print, "<socket state=%d timeout=%d incoming=%p remaining=%d>", self->state, self->timeout,
565-
self->incoming.pbuf, self->leftover_count);
576+
mp_printf(print, "<socket state=%d timeout=%d incoming=%p off=%d>", self->state, self->timeout,
577+
self->incoming.pbuf, self->recv_offset);
566578
}
567579

568580
// FIXME: Only supports two arguments at present
@@ -612,7 +624,7 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args
612624
socket->incoming.pbuf = NULL;
613625
socket->timeout = -1;
614626
socket->state = STATE_NEW;
615-
socket->leftover_count = 0;
627+
socket->recv_offset = 0;
616628
return socket;
617629
}
618630

@@ -749,7 +761,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
749761
socket2->incoming.pbuf = NULL;
750762
socket2->timeout = socket->timeout;
751763
socket2->state = STATE_CONNECTED;
752-
socket2->leftover_count = 0;
764+
socket2->recv_offset = 0;
753765
socket2->callback = MP_OBJ_NULL;
754766
tcp_arg(socket2->pcb.tcp, (void*)socket2);
755767
tcp_err(socket2->pcb.tcp, _lwip_tcp_error);

0 commit comments

Comments
 (0)