net: sockets: Implement recv() for STREAM sockets

Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
This commit is contained in:
Paul Sokolovsky 2017-06-12 22:18:16 +03:00 committed by Jukka Rissanen
commit 2b4a240859
2 changed files with 85 additions and 0 deletions

View file

@ -22,6 +22,7 @@ int zsock_connect(int sock, const struct sockaddr *addr, socklen_t addrlen);
int zsock_listen(int sock, int backlog);
int zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
ssize_t zsock_send(int sock, const void *buf, size_t len, int flags);
ssize_t zsock_recv(int sock, void *buf, size_t max_len, int flags);
#if defined(CONFIG_NET_SOCKETS_POSIX_NAMES)
#define socket zsock_socket
@ -31,6 +32,7 @@ ssize_t zsock_send(int sock, const void *buf, size_t len, int flags);
#define listen zsock_listen
#define accept zsock_accept
#define send zsock_send
#define recv zsock_recv
#define inet_ntop net_addr_ntop
#define inet_pton net_addr_pton

View file

@ -19,6 +19,16 @@
#define sock_is_eof(ctx) ((ctx)->user_data != NULL)
#define sock_set_eof(ctx) { (ctx)->user_data = INT_TO_POINTER(1); }
static inline void _k_fifo_wait_non_empty(struct k_fifo *fifo, int32_t timeout)
{
struct k_poll_event events[] = {
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY, fifo),
};
k_poll(events, ARRAY_SIZE(events), timeout);
}
int zsock_socket(int family, int type, int proto)
{
struct net_context *ctx;
@ -172,3 +182,76 @@ ssize_t zsock_send(int sock, const void *buf, size_t len, int flags)
return len;
}
static inline ssize_t zsock_recv_stream(struct net_context *ctx, void *buf, size_t max_len)
{
size_t recv_len = 0;
do {
struct net_pkt *pkt;
struct net_buf *frag;
u32_t frag_len;
if (sock_is_eof(ctx)) {
return 0;
}
_k_fifo_wait_non_empty(&ctx->recv_q, K_FOREVER);
pkt = k_fifo_peek_head(&ctx->recv_q);
if (!pkt) {
/* An expected reason is that wait was
* cancelled due to connection closure by peer.
*/
NET_DBG("NULL return from fifo");
continue;
}
frag = pkt->frags;
__ASSERT(frag != NULL,
"net_pkt has empty fragments on start!");
frag_len = frag->len;
recv_len = frag_len;
if (recv_len > max_len) {
recv_len = max_len;
}
/* Actually copy data to application buffer */
memcpy(buf, frag->data, recv_len);
if (recv_len != frag_len) {
net_buf_pull(frag, recv_len);
} else {
frag = net_pkt_frag_del(pkt, NULL, frag);
if (!frag) {
/* Finished processing head pkt in
* the fifo. Drop it from there.
*/
k_fifo_get(&ctx->recv_q, K_NO_WAIT);
if (net_pkt_eof(pkt)) {
sock_set_eof(ctx);
}
net_pkt_unref(pkt);
}
}
} while (recv_len == 0);
return recv_len;
}
ssize_t zsock_recv(int sock, void *buf, size_t max_len, int flags)
{
ARG_UNUSED(flags);
struct net_context *ctx = INT_TO_POINTER(sock);
enum net_sock_type sock_type = net_context_get_type(ctx);
size_t recv_len = 0;
if (sock_type == SOCK_DGRAM) {
__ASSERT(0, "DGRAM is not yet handled");
} else if (sock_type == SOCK_STREAM) {
return zsock_recv_stream(ctx, buf, max_len);
} else {
__ASSERT(0, "Unknown socket type");
}
return recv_len;
}