diff options
Diffstat (limited to 'samples/net/http_client/src/tcp_client.c')
-rw-r--r-- | samples/net/http_client/src/tcp_client.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/samples/net/http_client/src/tcp_client.c b/samples/net/http_client/src/tcp_client.c new file mode 100644 index 000000000..43403f46d --- /dev/null +++ b/samples/net/http_client/src/tcp_client.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "tcp_client.h" +#include "config.h" + +#include <net/net_core.h> +#include <net/net_if.h> +#include <net/nbuf.h> + +#include <misc/printk.h> + +static +int set_addr(struct sockaddr *sock_addr, const char *addr, uint16_t server_port) +{ + void *ptr = NULL; + int rc; + +#ifdef CONFIG_NET_IPV6 + net_sin6(sock_addr)->sin6_port = htons(server_port); + sock_addr->family = AF_INET6; + ptr = &(net_sin6(sock_addr)->sin6_addr); + rc = net_addr_pton(AF_INET6, addr, ptr); +#else + net_sin(sock_addr)->sin_port = htons(server_port); + sock_addr->family = AF_INET; + ptr = &(net_sin(sock_addr)->sin_addr); + rc = net_addr_pton(AF_INET, addr, ptr); +#endif + if (rc) { + printk("Invalid IP address: %s\n", addr); + } + + return rc; +} + +static +int if_addr_add(struct sockaddr *local_sock) +{ + void *p = NULL; + +#ifdef CONFIG_NET_IPV6 + p = net_if_ipv6_addr_add(net_if_get_default(), + &net_sin6(local_sock)->sin6_addr, + NET_ADDR_MANUAL, 0); +#else + p = net_if_ipv4_addr_add(net_if_get_default(), + &net_sin(local_sock)->sin_addr, + NET_ADDR_MANUAL, 0); +#endif + if (p) { + return 0; + } + + return -EINVAL; +} + +int tcp_set_local_addr(struct tcp_client_ctx *ctx, const char *local_addr) +{ + int rc; + + rc = set_addr(&ctx->local_sock, local_addr, 0); + if (rc) { + printk("set_addr (local) error\n"); + goto lb_exit; + } + + rc = if_addr_add(&ctx->local_sock); + if (rc) { + printk("if_addr_add error\n"); + } + +lb_exit: + return rc; +} + +static +void recv_cb(struct net_context *net_ctx, struct net_buf *rx, int status, + void *data) +{ + struct tcp_client_ctx *ctx = (struct tcp_client_ctx *)data; + + ARG_UNUSED(net_ctx); + + if (status) { + return; + } + + if (rx == NULL || net_nbuf_appdatalen(rx) == 0) { + goto lb_exit; + } + + /* receive_cb must take ownership of the rx buffer */ + if (ctx->receive_cb) { + ctx->receive_cb(ctx, rx); + return; + } + +lb_exit: + net_buf_unref(rx); +} + +int tcp_connect(struct tcp_client_ctx *ctx, const char *server_addr, + uint16_t server_port) +{ +#if CONFIG_NET_IPV6 + socklen_t addr_len = sizeof(struct sockaddr_in6); + sa_family_t family = AF_INET6; +#else + socklen_t addr_len = sizeof(struct sockaddr_in); + sa_family_t family = AF_INET; +#endif + struct sockaddr server_sock; + int rc; + + rc = net_context_get(family, SOCK_STREAM, IPPROTO_TCP, &ctx->net_ctx); + if (rc) { + printk("net_context_get error\n"); + return rc; + } + + rc = net_context_bind(ctx->net_ctx, &ctx->local_sock, addr_len); + if (rc) { + printk("net_context_bind error\n"); + goto lb_exit; + } + + rc = set_addr(&server_sock, server_addr, server_port); + if (rc) { + printk("set_addr (server) error\n"); + goto lb_exit; + } + + rc = net_context_connect(ctx->net_ctx, &server_sock, addr_len, NULL, + ctx->timeout, NULL); + if (rc) { + printk("net_context_connect error\n"); + goto lb_exit; + } + + (void)net_context_recv(ctx->net_ctx, recv_cb, K_NO_WAIT, ctx); + + return 0; + +lb_exit: + net_context_put(ctx->net_ctx); + + return rc; +} + +int tcp_disconnect(struct tcp_client_ctx *ctx) +{ + if (ctx->net_ctx) { + net_context_put(ctx->net_ctx); + ctx->net_ctx = NULL; + } + + return 0; +} |