Merge pull request #13701 from miri64/lwip_sock/enh/recv_buf

lwip_sock: provide implementation for `sock_*_recv_buf()`
This commit is contained in:
Martine Lenders 2020-05-26 21:33:09 +02:00 committed by GitHub
commit a38428b8f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 185 additions and 29 deletions

View File

@ -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;
}

View File

@ -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,

View File

@ -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());

View File

@ -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());