net: sockets: Implement non-blocking mode.

Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
This commit is contained in:
Paul Sokolovsky 2017-07-11 01:22:40 +03:00 committed by Jukka Rissanen
commit 1abb89f640
2 changed files with 97 additions and 10 deletions

View file

@ -23,6 +23,7 @@ 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);
int zsock_fcntl(int sock, int cmd, int flags);
#if defined(CONFIG_NET_SOCKETS_POSIX_NAMES)
#define socket zsock_socket
@ -33,6 +34,7 @@ ssize_t zsock_recv(int sock, void *buf, size_t max_len, int flags);
#define accept zsock_accept
#define send zsock_send
#define recv zsock_recv
#define fcntl zsock_fcntl
#define inet_ntop net_addr_ntop
#define inet_pton net_addr_pton

View file

@ -9,15 +9,36 @@
#define NET_LOG_ENABLED 1
#endif
/* libc headers */
#include <sys/fcntl.h>
/* Zephyr headers */
#include <net/net_context.h>
#include <net/net_pkt.h>
#include <net/socket.h>
#define SOCK_EOF 1
#define SOCK_NONBLOCK 2
#define SET_ERRNO(x) \
{ int _err = x; if (_err < 0) { errno = -_err; return -1; } }
#define sock_is_eof(ctx) ((ctx)->user_data != NULL)
#define sock_set_eof(ctx) { (ctx)->user_data = INT_TO_POINTER(1); }
static inline void sock_set_flag(struct net_context *ctx, u32_t mask,
u32_t flag)
{
u32_t val = POINTER_TO_INT(ctx->user_data);
val = (val & mask) | flag;
(ctx)->user_data = INT_TO_POINTER(val);
}
static inline u32_t sock_get_flag(struct net_context *ctx, u32_t mask)
{
return POINTER_TO_INT(ctx->user_data) & mask;
}
#define sock_is_eof(ctx) sock_get_flag(ctx, SOCK_EOF)
#define sock_set_eof(ctx) sock_set_flag(ctx, SOCK_EOF, SOCK_EOF)
#define sock_is_nonblock(ctx) sock_get_flag(ctx, SOCK_NONBLOCK)
static inline void _k_fifo_wait_non_empty(struct k_fifo *fifo, int32_t timeout)
{
@ -181,10 +202,21 @@ ssize_t zsock_send(int sock, const void *buf, size_t len, int flags)
{
ARG_UNUSED(flags);
int err;
struct net_pkt *send_pkt;
s32_t timeout = K_FOREVER;
struct net_context *ctx = INT_TO_POINTER(sock);
struct net_pkt *send_pkt = net_pkt_get_tx(ctx, K_FOREVER);
size_t max_len = net_if_get_mtu(net_context_get_iface(ctx));
if (sock_is_nonblock(ctx)) {
timeout = K_NO_WAIT;
}
send_pkt = net_pkt_get_tx(ctx, timeout);
if (!send_pkt) {
errno = EAGAIN;
return -1;
}
/* Make sure we don't send more data in one packet than
* MTU allows. Optimize for number of branches in the code.
*/
@ -197,8 +229,14 @@ ssize_t zsock_send(int sock, const void *buf, size_t len, int flags)
len = max_len;
}
len = net_pkt_append(send_pkt, len, buf, K_FOREVER);
err = net_context_send(send_pkt, /*cb*/NULL, K_FOREVER, NULL, NULL);
len = net_pkt_append(send_pkt, len, buf, timeout);
if (!len) {
net_pkt_unref(send_pkt);
errno = EAGAIN;
return -1;
}
err = net_context_send(send_pkt, /*cb*/NULL, timeout, NULL, NULL);
if (err < 0) {
net_pkt_unref(send_pkt);
errno = -err;
@ -211,6 +249,11 @@ ssize_t zsock_send(int sock, const void *buf, size_t len, int flags)
static inline ssize_t zsock_recv_stream(struct net_context *ctx, void *buf, size_t max_len)
{
size_t recv_len = 0;
s32_t timeout = K_FOREVER;
if (sock_is_nonblock(ctx)) {
timeout = K_NO_WAIT;
}
do {
struct net_pkt *pkt;
@ -221,14 +264,19 @@ static inline ssize_t zsock_recv_stream(struct net_context *ctx, void *buf, size
return 0;
}
_k_fifo_wait_non_empty(&ctx->recv_q, K_FOREVER);
_k_fifo_wait_non_empty(&ctx->recv_q, timeout);
pkt = k_fifo_peek_head(&ctx->recv_q);
if (!pkt) {
/* An expected reason is that wait was
* cancelled due to connection closure by peer.
/* Either timeout expired, or wait was cancelled
* due to connection closure by peer.
*/
NET_DBG("NULL return from fifo");
continue;
if (sock_is_eof(ctx)) {
return 0;
} else {
errno = EAGAIN;
return -1;
}
}
frag = pkt->frags;
@ -272,7 +320,18 @@ ssize_t zsock_recv(int sock, void *buf, size_t max_len, int flags)
if (sock_type == SOCK_DGRAM) {
struct net_pkt *pkt = k_fifo_get(&ctx->recv_q, K_FOREVER);
struct net_pkt *pkt;
s32_t timeout = K_FOREVER;
if (sock_is_nonblock(ctx)) {
timeout = K_NO_WAIT;
}
pkt = k_fifo_get(&ctx->recv_q, timeout);
if (!pkt) {
errno = EAGAIN;
return -1;
}
recv_len = net_pkt_appdatalen(pkt);
if (recv_len > max_len) {
@ -290,3 +349,29 @@ ssize_t zsock_recv(int sock, void *buf, size_t max_len, int flags)
return recv_len;
}
/* As this is limited function, we don't follow POSIX signature, with
* "..." instead of last arg.
*/
int zsock_fcntl(int sock, int cmd, int flags)
{
struct net_context *ctx = INT_TO_POINTER(sock);
switch (cmd) {
case F_GETFL:
if (sock_is_nonblock(ctx)) {
return O_NONBLOCK;
}
return 0;
case F_SETFL:
if (flags & O_NONBLOCK) {
sock_set_flag(ctx, SOCK_NONBLOCK, SOCK_NONBLOCK);
} else {
sock_set_flag(ctx, SOCK_NONBLOCK, 0);
}
return 0;
default:
errno = EINVAL;
return -1;
}
}