Merge pull request #13701 from miri64/lwip_sock/enh/recv_buf
lwip_sock: provide implementation for `sock_*_recv_buf()`
This commit is contained in:
commit
a38428b8f2
@ -106,20 +106,15 @@ static uint16_t _ip6_addr_to_netif(const ip6_addr_p_t *_addr)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _parse_iphdr(const struct netbuf *buf, void *data, size_t max_len,
|
||||
static int _parse_iphdr(struct netbuf *buf, void **data, void **ctx,
|
||||
sock_ip_ep_t *remote)
|
||||
{
|
||||
uint8_t *data_ptr = buf->p->payload;
|
||||
size_t data_len = buf->p->len;
|
||||
uint8_t *data_ptr = buf->ptr->payload;
|
||||
size_t data_len = buf->ptr->len;
|
||||
|
||||
assert(buf->p->next == NULL); /* TODO this might not be generally the case
|
||||
* check later with larger payloads */
|
||||
switch (data_ptr[0] >> 4) {
|
||||
#if LWIP_IPV4
|
||||
case 4:
|
||||
if ((data_len - sizeof(struct ip_hdr)) > max_len) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (remote != NULL) {
|
||||
struct ip_hdr *iphdr = (struct ip_hdr *)data_ptr;
|
||||
|
||||
@ -134,9 +129,6 @@ static int _parse_iphdr(const struct netbuf *buf, void *data, size_t max_len,
|
||||
#endif
|
||||
#if LWIP_IPV6
|
||||
case 6:
|
||||
if ((data_len - sizeof(struct ip6_hdr)) > max_len) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (remote != NULL) {
|
||||
struct ip6_hdr *iphdr = (struct ip6_hdr *)data_ptr;
|
||||
|
||||
@ -150,24 +142,63 @@ static int _parse_iphdr(const struct netbuf *buf, void *data, size_t max_len,
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
netbuf_delete(buf);
|
||||
return -EPROTO;
|
||||
}
|
||||
memcpy(data, data_ptr, data_len);
|
||||
*data = data_ptr;
|
||||
*ctx = buf;
|
||||
return (ssize_t)data_len;
|
||||
}
|
||||
|
||||
ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
|
||||
uint32_t timeout, sock_ip_ep_t *remote)
|
||||
{
|
||||
void *pkt = NULL;
|
||||
struct netbuf *ctx = NULL;
|
||||
uint8_t *ptr = data;
|
||||
ssize_t res, ret = 0;
|
||||
bool nobufs = false;
|
||||
|
||||
assert((sock != NULL) && (data != NULL) && (max_len > 0));
|
||||
while ((res = sock_ip_recv_buf(sock, &pkt, (void **)&ctx, timeout,
|
||||
remote)) > 0) {
|
||||
if (ctx->p->tot_len > (ssize_t)max_len) {
|
||||
nobufs = true;
|
||||
/* progress context to last element */
|
||||
while (netbuf_next(ctx) == 0) {}
|
||||
continue;
|
||||
}
|
||||
memcpy(ptr, pkt, res);
|
||||
ptr += res;
|
||||
ret += res;
|
||||
}
|
||||
return (nobufs) ? -ENOBUFS : ((res < 0) ? res : ret);
|
||||
}
|
||||
|
||||
ssize_t sock_ip_recv_buf(sock_ip_t *sock, void **data, void **ctx,
|
||||
uint32_t timeout, sock_ip_ep_t *remote)
|
||||
{
|
||||
struct netbuf *buf;
|
||||
int res;
|
||||
|
||||
assert((sock != NULL) && (data != NULL) && (max_len > 0));
|
||||
assert((sock != NULL) && (data != NULL) && (ctx != NULL));
|
||||
buf = *ctx;
|
||||
if (buf != NULL) {
|
||||
if (netbuf_next(buf) == -1) {
|
||||
*data = NULL;
|
||||
netbuf_delete(buf);
|
||||
*ctx = NULL;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
*data = buf->ptr->payload;
|
||||
return buf->ptr->len;
|
||||
}
|
||||
}
|
||||
if ((res = lwip_sock_recv(sock->base.conn, timeout, &buf)) < 0) {
|
||||
return res;
|
||||
}
|
||||
res = _parse_iphdr(buf, data, max_len, remote);
|
||||
netbuf_delete(buf);
|
||||
res = _parse_iphdr(buf, data, ctx, remote);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -71,19 +71,52 @@ int sock_udp_get_remote(sock_udp_t *sock, sock_udp_ep_t *ep)
|
||||
ssize_t sock_udp_recv(sock_udp_t *sock, void *data, size_t max_len,
|
||||
uint32_t timeout, sock_udp_ep_t *remote)
|
||||
{
|
||||
uint8_t *data_ptr = data;
|
||||
void *pkt = NULL;
|
||||
void *ctx = NULL;
|
||||
uint8_t *ptr = data;
|
||||
ssize_t res, ret = 0;
|
||||
bool nobufs = false;
|
||||
|
||||
assert((sock != NULL) && (data != NULL) && (max_len > 0));
|
||||
while ((res = sock_udp_recv_buf(sock, &pkt, &ctx, timeout,
|
||||
remote)) > 0) {
|
||||
struct netbuf *buf = ctx;
|
||||
if (buf->p->tot_len > (ssize_t)max_len) {
|
||||
nobufs = true;
|
||||
/* progress context to last element */
|
||||
while (netbuf_next(ctx) == 0) {}
|
||||
continue;
|
||||
}
|
||||
memcpy(ptr, pkt, res);
|
||||
ptr += res;
|
||||
ret += res;
|
||||
}
|
||||
return (nobufs) ? -ENOBUFS : ((res < 0) ? res : ret);
|
||||
}
|
||||
|
||||
ssize_t sock_udp_recv_buf(sock_udp_t *sock, void **data, void **ctx,
|
||||
uint32_t timeout, sock_udp_ep_t *remote)
|
||||
{
|
||||
struct netbuf *buf;
|
||||
int res;
|
||||
|
||||
assert((sock != NULL) && (data != NULL) && (max_len > 0));
|
||||
assert((sock != NULL) && (data != NULL) && (ctx != NULL));
|
||||
buf = *ctx;
|
||||
if (buf != NULL) {
|
||||
if (netbuf_next(buf) == -1) {
|
||||
*data = NULL;
|
||||
netbuf_delete(buf);
|
||||
*ctx = NULL;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
*data = buf->ptr->payload;
|
||||
return buf->ptr->len;
|
||||
}
|
||||
}
|
||||
if ((res = lwip_sock_recv(sock->base.conn, timeout, &buf)) < 0) {
|
||||
return res;
|
||||
}
|
||||
res = buf->p->tot_len;
|
||||
if ((unsigned)res > max_len) {
|
||||
netbuf_delete(buf);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (remote != NULL) {
|
||||
/* convert remote */
|
||||
size_t addr_len;
|
||||
@ -113,13 +146,9 @@ ssize_t sock_udp_recv(sock_udp_t *sock, void *data, size_t max_len,
|
||||
memcpy(&remote->addr, &buf->addr, addr_len);
|
||||
remote->port = buf->port;
|
||||
}
|
||||
/* copy data */
|
||||
for (struct pbuf *q = buf->p; q != NULL; q = q->next) {
|
||||
memcpy(data_ptr, q->payload, q->len);
|
||||
data_ptr += q->len;
|
||||
}
|
||||
netbuf_delete(buf);
|
||||
return (ssize_t)res;
|
||||
*data = buf->ptr->payload;
|
||||
*ctx = buf;
|
||||
return (ssize_t)buf->ptr->len;
|
||||
}
|
||||
|
||||
ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len,
|
||||
|
||||
@ -303,6 +303,27 @@ static void test_sock_ip_recv4__non_blocking(void)
|
||||
expect(_check_net());
|
||||
}
|
||||
|
||||
static void test_sock_ip_recv_buf4__success(void)
|
||||
{
|
||||
static const sock_ip_ep_t local = { .family = AF_INET };
|
||||
static const sock_ip_ep_t remote = { .addr = { .ipv4_u32 = _TEST_ADDR4_REMOTE },
|
||||
.family = AF_INET };
|
||||
void *data = NULL, *ctx = NULL;
|
||||
|
||||
expect(0 == sock_ip_create(&_sock, &local, &remote, _TEST_PROTO,
|
||||
SOCK_FLAGS_REUSE_EP));
|
||||
expect(_inject_4packet(_TEST_ADDR4_REMOTE, _TEST_ADDR4_LOCAL, _TEST_PROTO, "ABCD",
|
||||
sizeof("ABCD"), _TEST_NETIF));
|
||||
assert(sizeof("ABCD") == sock_ip_recv_buf(&_sock, &data, &ctx,
|
||||
SOCK_NO_TIMEOUT, NULL));
|
||||
assert(data != NULL);
|
||||
assert(ctx != NULL);
|
||||
assert(0 == sock_ip_recv_buf(&_sock, &data, &ctx, SOCK_NO_TIMEOUT, NULL));
|
||||
assert(data == NULL);
|
||||
assert(ctx == NULL);
|
||||
assert(_check_net());
|
||||
}
|
||||
|
||||
static void test_sock_ip_send4__EAFNOSUPPORT(void)
|
||||
{
|
||||
static const sock_ip_ep_t remote = { .addr = { .ipv4_u32 = _TEST_ADDR4_REMOTE },
|
||||
@ -823,6 +844,29 @@ static void test_sock_ip_recv6__non_blocking(void)
|
||||
expect(_check_net());
|
||||
}
|
||||
|
||||
static void test_sock_ip_recv_buf6__success(void)
|
||||
{
|
||||
static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_REMOTE };
|
||||
static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_LOCAL };
|
||||
static const sock_ip_ep_t local = { .family = AF_INET6 };
|
||||
static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE },
|
||||
.family = AF_INET6 };
|
||||
void *data = NULL, *ctx = NULL;
|
||||
|
||||
assert(0 == sock_ip_create(&_sock, &local, &remote, _TEST_PROTO,
|
||||
SOCK_FLAGS_REUSE_EP));
|
||||
assert(_inject_6packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
|
||||
sizeof("ABCD"), _TEST_NETIF));
|
||||
assert(sizeof("ABCD") == sock_ip_recv_buf(&_sock, &data, &ctx, SOCK_NO_TIMEOUT,
|
||||
NULL));
|
||||
assert(data != NULL);
|
||||
assert(ctx != NULL);
|
||||
assert(0 == sock_ip_recv_buf(&_sock, &data, &ctx, SOCK_NO_TIMEOUT, NULL));
|
||||
assert(data == NULL);
|
||||
assert(ctx == NULL);
|
||||
assert(_check_net());
|
||||
}
|
||||
|
||||
static void test_sock_ip_send6__EAFNOSUPPORT(void)
|
||||
{
|
||||
static const sock_ip_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE },
|
||||
@ -1119,6 +1163,7 @@ int main(void)
|
||||
CALL(test_sock_ip_recv4__unsocketed_with_remote());
|
||||
CALL(test_sock_ip_recv4__with_timeout());
|
||||
CALL(test_sock_ip_recv4__non_blocking());
|
||||
CALL(test_sock_ip_recv_buf4__success());
|
||||
_prepare_send_checks();
|
||||
CALL(test_sock_ip_send4__EAFNOSUPPORT());
|
||||
CALL(test_sock_ip_send4__EINVAL_addr());
|
||||
@ -1163,6 +1208,7 @@ int main(void)
|
||||
CALL(test_sock_ip_recv6__unsocketed_with_remote());
|
||||
CALL(test_sock_ip_recv6__with_timeout());
|
||||
CALL(test_sock_ip_recv6__non_blocking());
|
||||
CALL(test_sock_ip_recv_buf6__success());
|
||||
_prepare_send_checks();
|
||||
CALL(test_sock_ip_send6__EAFNOSUPPORT());
|
||||
CALL(test_sock_ip_send6__EINVAL_addr());
|
||||
|
||||
@ -393,6 +393,29 @@ static void test_sock_udp_recv4__non_blocking(void)
|
||||
expect(_check_net());
|
||||
}
|
||||
|
||||
static void test_sock_udp_recv_buf4__success(void)
|
||||
{
|
||||
static const sock_udp_ep_t local = { .family = AF_INET,
|
||||
.port = _TEST_PORT_LOCAL };
|
||||
static const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = _TEST_ADDR4_REMOTE },
|
||||
.family = AF_INET,
|
||||
.port = _TEST_PORT_REMOTE };
|
||||
void *data = NULL, *ctx = NULL;
|
||||
|
||||
expect(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
|
||||
expect(_inject_4packet(_TEST_ADDR4_REMOTE, _TEST_ADDR4_LOCAL, _TEST_PORT_REMOTE,
|
||||
_TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
|
||||
_TEST_NETIF));
|
||||
assert(sizeof("ABCD") == sock_udp_recv_buf(&_sock, &data, &ctx,
|
||||
SOCK_NO_TIMEOUT, NULL));
|
||||
assert(data != NULL);
|
||||
assert(ctx != NULL);
|
||||
assert(0 == sock_udp_recv_buf(&_sock, &data, &ctx, SOCK_NO_TIMEOUT, NULL));
|
||||
assert(data == NULL);
|
||||
assert(ctx == NULL);
|
||||
assert(_check_net());
|
||||
}
|
||||
|
||||
static void test_sock_udp_send4__EAFNOSUPPORT(void)
|
||||
{
|
||||
static const sock_udp_ep_t remote = { .addr = { .ipv4_u32 = _TEST_ADDR4_REMOTE },
|
||||
@ -1033,6 +1056,31 @@ static void test_sock_udp_recv6__non_blocking(void)
|
||||
expect(_check_net());
|
||||
}
|
||||
|
||||
static void test_sock_udp_recv_buf6__success(void)
|
||||
{
|
||||
static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR6_REMOTE };
|
||||
static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR6_LOCAL };
|
||||
static const sock_udp_ep_t local = { .family = AF_INET6,
|
||||
.port = _TEST_PORT_LOCAL };
|
||||
static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE },
|
||||
.family = AF_INET6,
|
||||
.port = _TEST_PORT_REMOTE };
|
||||
void *data = NULL, *ctx = NULL;
|
||||
|
||||
assert(0 == sock_udp_create(&_sock, &local, &remote, SOCK_FLAGS_REUSE_EP));
|
||||
assert(_inject_6packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
|
||||
_TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
|
||||
_TEST_NETIF));
|
||||
assert(sizeof("ABCD") == sock_udp_recv_buf(&_sock, &data, &ctx, SOCK_NO_TIMEOUT,
|
||||
NULL));
|
||||
assert(data != NULL);
|
||||
assert(ctx != NULL);
|
||||
assert(0 == sock_udp_recv_buf(&_sock, &data, &ctx, SOCK_NO_TIMEOUT, NULL));
|
||||
assert(data == NULL);
|
||||
assert(ctx == NULL);
|
||||
assert(_check_net());
|
||||
}
|
||||
|
||||
static void test_sock_udp_send6__EAFNOSUPPORT(void)
|
||||
{
|
||||
static const sock_udp_ep_t remote = { .addr = { .ipv6 = _TEST_ADDR6_REMOTE },
|
||||
@ -1360,6 +1408,7 @@ int main(void)
|
||||
CALL(test_sock_udp_recv4__unsocketed_with_remote());
|
||||
CALL(test_sock_udp_recv4__with_timeout());
|
||||
CALL(test_sock_udp_recv4__non_blocking());
|
||||
CALL(test_sock_udp_recv_buf4__success());
|
||||
_prepare_send_checks();
|
||||
CALL(test_sock_udp_send4__EAFNOSUPPORT());
|
||||
CALL(test_sock_udp_send4__EINVAL_addr());
|
||||
@ -1407,6 +1456,7 @@ int main(void)
|
||||
CALL(test_sock_udp_recv6__unsocketed_with_remote());
|
||||
CALL(test_sock_udp_recv6__with_timeout());
|
||||
CALL(test_sock_udp_recv6__non_blocking());
|
||||
CALL(test_sock_udp_recv_buf6__success());
|
||||
_prepare_send_checks();
|
||||
CALL(test_sock_udp_send6__EAFNOSUPPORT());
|
||||
CALL(test_sock_udp_send6__EINVAL_addr());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user