mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
vfs_lwip: receive payload without breaking refcount
lwip uses a sophisticated reference-counting scheme in chains of pbufs, which the former manual implementation of read() for TCP data broke. Using pbuf_free_header() keeps the chain intact and also relieves our implementation from the burden of "offset" maintenance. Fixes #4722
This commit is contained in:
parent
7858c00539
commit
84c5a7b0cd
@ -401,8 +401,8 @@ class Lwip::Nic_netif
|
||||
* pbuf into the packet.
|
||||
*/
|
||||
char *dst = tx.packet_content(packet);
|
||||
for(struct pbuf *q = p; q != 0; q = q->next) {
|
||||
char const *src = (char*)q->payload;
|
||||
for (struct pbuf *q = p; q != nullptr; q = q->next) {
|
||||
char const *src = (char const *)q->payload;
|
||||
Genode::memcpy(dst, src, q->len);
|
||||
dst += q->len;
|
||||
}
|
||||
|
@ -1113,7 +1113,6 @@ class Lwip::Tcp_socket_dir final :
|
||||
|
||||
/* queue of received data */
|
||||
pbuf *_recv_pbuf = nullptr;
|
||||
u16_t _recv_off = 0;
|
||||
|
||||
Open_result _accept_new_socket(Vfs::File_system &fs,
|
||||
Genode::Allocator &alloc,
|
||||
@ -1195,13 +1194,17 @@ class Lwip::Tcp_socket_dir final :
|
||||
/**
|
||||
* chain a buffer to the queue
|
||||
*/
|
||||
void recv(struct pbuf *buf)
|
||||
err_t recv(struct pbuf *buf)
|
||||
{
|
||||
if (_recv_pbuf && buf) {
|
||||
if (!buf)
|
||||
return ERR_ARG;
|
||||
|
||||
if (_recv_pbuf)
|
||||
pbuf_cat(_recv_pbuf, buf);
|
||||
} else {
|
||||
else
|
||||
_recv_pbuf = buf;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1325,24 +1328,10 @@ class Lwip::Tcp_socket_dir final :
|
||||
: Read_result::READ_OK;
|
||||
}
|
||||
|
||||
u16_t const ucount = count;
|
||||
u16_t const n = pbuf_copy_partial(_recv_pbuf, dst, ucount, _recv_off);
|
||||
_recv_off += n;
|
||||
{
|
||||
u16_t new_off;
|
||||
pbuf *new_head = pbuf_skip(_recv_pbuf, _recv_off, &new_off);
|
||||
if (new_head != NULL && new_head != _recv_pbuf) {
|
||||
/* increment the references on the new head */
|
||||
pbuf_ref(new_head);
|
||||
/* free the buffers chained to the old head */
|
||||
pbuf_free(_recv_pbuf);
|
||||
}
|
||||
u16_t const ucount = min(count, (file_size)0xffff);
|
||||
u16_t const n = pbuf_copy_partial(_recv_pbuf, dst, ucount, 0);
|
||||
|
||||
if (!new_head)
|
||||
pbuf_free(_recv_pbuf);
|
||||
_recv_pbuf = new_head;
|
||||
_recv_off = new_off;
|
||||
}
|
||||
_recv_pbuf = pbuf_free_header(_recv_pbuf, n);
|
||||
|
||||
/* ACK the remote */
|
||||
if (_pcb)
|
||||
@ -1358,8 +1347,8 @@ class Lwip::Tcp_socket_dir final :
|
||||
|
||||
case Lwip_file_handle::PEEK:
|
||||
if (_recv_pbuf != nullptr) {
|
||||
u16_t const ucount = count;
|
||||
u16_t const n = pbuf_copy_partial(_recv_pbuf, dst, ucount, _recv_off);
|
||||
u16_t const ucount = min(count, (file_size)0xffff);
|
||||
u16_t const n = pbuf_copy_partial(_recv_pbuf, dst, ucount, 0);
|
||||
out_count = n;
|
||||
}
|
||||
return Read_result::READ_OK;
|
||||
@ -1658,16 +1647,18 @@ err_t tcp_recv_callback(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t)
|
||||
return ERR_ABRT;
|
||||
}
|
||||
|
||||
err_t err = ERR_OK;
|
||||
|
||||
Lwip::Tcp_socket_dir *socket_dir = static_cast<Lwip::Tcp_socket_dir *>(arg);
|
||||
if (p == NULL) {
|
||||
socket_dir->shutdown();
|
||||
} else {
|
||||
socket_dir->recv(p);
|
||||
err = socket_dir->recv(p);
|
||||
}
|
||||
|
||||
socket_dir->wakeup_vfs_user();
|
||||
socket_dir->process_read_ready();
|
||||
return ERR_OK;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user