Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
286 changes: 164 additions & 122 deletions subsys/net/lib/app/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,95 @@ static int resolve_name(struct net_app_ctx *ctx,
}
#endif /* CONFIG_DNS_RESOLVER */

static int try_resolve(struct net_app_ctx *ctx,
const char *peer_addr_str,
enum dns_query_type type,
s32_t timeout)
{
#if !defined(CONFIG_DNS_RESOLVER)
NET_ERR("Invalid IP address %s", peer_addr_str);
return -EINVAL;
#else
int ret;

ret = resolve_name(ctx, peer_addr_str, type, timeout);
if (ret < 0) {
NET_ERR("Cannot resolve %s (%d)", peer_addr_str, ret);
}

return ret;
#endif
}

static int set_remote_addr(struct net_app_ctx *ctx,
struct sockaddr *remote_addr,
const char *peer_addr_str,
bool peer_addr_ok,
s32_t timeout)
{
int ret;

if (peer_addr_ok && remote_addr->sa_family == AF_INET6) {
#if defined(CONFIG_NET_IPV6)
memcpy(&ctx->ipv6.remote, remote_addr,
sizeof(struct sockaddr));
ctx->default_ctx = &ctx->ipv6;
return 0;
#else
return -EAFNOSUPPORT;
#endif
}

if (peer_addr_ok && remote_addr->sa_family == AF_INET) {
#if defined(CONFIG_NET_IPV4)
memcpy(&ctx->ipv4.remote, remote_addr,
sizeof(struct sockaddr));
ctx->default_ctx = &ctx->ipv4;
return 0;
#else
return -EAFNOSUPPORT;
#endif
}

#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
/* Could be hostname, try DNS if configured. */
ret = try_resolve(ctx, peer_addr_str, DNS_QUERY_TYPE_AAAA, timeout);
if (ret < 0) {
return ret;
}

ctx->default_ctx = &ctx->ipv6;
return 0;
#endif /* IPV6 && !IPV4 */

#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
ret = try_resolve(ctx, peer_addr_str, DNS_QUERY_TYPE_A, timeout);
if (ret < 0) {
return ret;
}

ctx->default_ctx = &ctx->ipv4;
return 0;
#endif /* IPV6 && !IPV4 */

#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_IPV6)
ret = try_resolve(ctx, peer_addr_str, DNS_QUERY_TYPE_A, timeout);
if (ret < 0) {
ret = try_resolve(ctx, peer_addr_str, DNS_QUERY_TYPE_AAAA,
timeout);
if (ret < 0) {
return ret;
}

ctx->default_ctx = &ctx->ipv6;
return 0;
}

ctx->default_ctx = &ctx->ipv4;
return 0;
#endif /* IPV4 && IPV6 */
}

static int get_port_number(const char *peer_addr_str,
char *buf,
size_t buf_len)
Expand Down Expand Up @@ -168,132 +257,26 @@ static int get_port_number(const char *peer_addr_str,
return 0;
}

static int set_remote_addr(struct net_app_ctx *ctx,
const char *peer_addr_str,
u16_t peer_port,
s32_t timeout)
static void close_net_ctx(struct net_app_ctx *ctx)
{
char addr_str[INET6_ADDRSTRLEN + 1];
char *addr;
int ret;

/* If the peer string contains port number, use that and ignore
* the port number parameter.
*/
ret = get_port_number(peer_addr_str, addr_str, sizeof(addr_str));
if (ret > 0) {
addr = addr_str;
peer_port = ret;
} else {
addr = (char *)peer_addr_str;
#if defined(CONFIG_NET_IPV6)
if (ctx->ipv6.ctx) {
net_context_put(ctx->ipv6.ctx);
ctx->ipv6.ctx = NULL;
}

#if defined(CONFIG_NET_IPV6) && !defined(CONFIG_NET_IPV4)
ret = net_addr_pton(AF_INET6, addr,
&net_sin6(&ctx->ipv6.remote)->sin6_addr);
if (ret < 0) {
/* Could be hostname, try DNS if configured. */
#if !defined(CONFIG_DNS_RESOLVER)
NET_ERR("Invalid IPv6 address %s", addr);
return -EINVAL;
#else
ret = resolve_name(ctx, addr, DNS_QUERY_TYPE_AAAA, timeout);
if (ret < 0) {
NET_ERR("Cannot resolve %s (%d)", addr, ret);
return ret;
}
#endif
#if defined(CONFIG_NET_IPV4)
if (ctx->ipv4.ctx) {
net_context_put(ctx->ipv4.ctx);
ctx->ipv4.ctx = NULL;
}

net_sin6(&ctx->ipv6.remote)->sin6_port = htons(peer_port);
net_sin6(&ctx->ipv6.remote)->sin6_family = AF_INET6;
ctx->ipv6.remote.sa_family = AF_INET6;
ctx->default_ctx = &ctx->ipv6;
#endif /* IPV6 && !IPV4 */

#if defined(CONFIG_NET_IPV4) && !defined(CONFIG_NET_IPV6)
ret = net_addr_pton(AF_INET, addr,
&net_sin(&ctx->ipv4.remote)->sin_addr);
if (ret < 0) {
/* Could be hostname, try DNS if configured. */
#if !defined(CONFIG_DNS_RESOLVER)
NET_ERR("Invalid IPv4 address %s", addr);
return -EINVAL;
#else
ret = resolve_name(ctx, addr, DNS_QUERY_TYPE_A, timeout);
if (ret < 0) {
NET_ERR("Cannot resolve %s (%d)", addr, ret);
return ret;
}
#endif
#if defined(CONFIG_NET_APP_SERVER)
if (ctx->server.net_ctx) {
net_context_put(ctx->server.net_ctx);
ctx->server.net_ctx = NULL;
}

net_sin(&ctx->ipv4.remote)->sin_port = htons(peer_port);
net_sin(&ctx->ipv4.remote)->sin_family = AF_INET;
ctx->ipv4.remote.sa_family = AF_INET;
ctx->default_ctx = &ctx->ipv4;
#endif /* IPV6 && !IPV4 */

#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_IPV6)
ret = net_addr_pton(AF_INET, addr,
&net_sin(&ctx->ipv4.remote)->sin_addr);
if (ret < 0) {
ret = net_addr_pton(AF_INET6, addr,
&net_sin6(&ctx->ipv6.remote)->sin6_addr);
if (ret < 0) {
/* Could be hostname, try DNS if configured. */
#if !defined(CONFIG_DNS_RESOLVER)
NET_ERR("Invalid IPv4 or IPv6 address %s", addr);
return -EINVAL;
#else
ret = resolve_name(ctx, addr,
DNS_QUERY_TYPE_A, timeout);
if (ret < 0) {
ret = resolve_name(ctx, addr,
DNS_QUERY_TYPE_AAAA,
timeout);
if (ret < 0) {
NET_ERR("Cannot resolve %s (%d)",
addr, ret);
return ret;
}

goto ipv6;
}

goto ipv4;
#endif /* !CONFIG_DNS_RESOLVER */
} else {
#if defined(CONFIG_DNS_RESOLVER)
ipv6:
#endif
net_sin6(&ctx->ipv6.remote)->sin6_port =
htons(peer_port);
net_sin6(&ctx->ipv6.remote)->sin6_family = AF_INET6;
ctx->ipv6.remote.sa_family = AF_INET6;
ctx->default_ctx = &ctx->ipv6;
}
} else {
#if defined(CONFIG_DNS_RESOLVER)
ipv4:
#endif
net_sin(&ctx->ipv4.remote)->sin_port = htons(peer_port);
net_sin(&ctx->ipv4.remote)->sin_family = AF_INET;
ctx->ipv4.remote.sa_family = AF_INET;
ctx->default_ctx = &ctx->ipv4;
}
#endif /* IPV4 && IPV6 */

/* If we have not yet figured out what is the protocol family,
* then we cannot continue.
*/
if (!ctx->default_ctx ||
ctx->default_ctx->remote.sa_family == AF_UNSPEC) {
NET_ERR("Unknown protocol family.");
return -EPFNOSUPPORT;
}

return 0;
}

int net_app_init_client(struct net_app_ctx *ctx,
Expand All @@ -306,8 +289,11 @@ int net_app_init_client(struct net_app_ctx *ctx,
s32_t timeout,
void *user_data)
{
const char *base_peer_addr = peer_addr_str;
char base_addr_str[INET6_ADDRSTRLEN + 1];
struct sockaddr remote_addr;
struct sockaddr addr;
int ret;
int ret, addr_ok = false;

if (!ctx) {
return -EINVAL;
Expand All @@ -318,11 +304,54 @@ int net_app_init_client(struct net_app_ctx *ctx,
}

memset(&addr, 0, sizeof(addr));
memset(&remote_addr, 0, sizeof(remote_addr));

if (peer_addr) {
memcpy(&remote_addr, peer_addr, sizeof(remote_addr));
} else if (peer_addr_str) {
/* If the peer string contains port number, use that and
* ignore the port number parameter.
*/
ret = get_port_number(peer_addr_str, base_addr_str,
sizeof(base_addr_str));
if (ret > 0) {
base_peer_addr = base_addr_str;
peer_port = ret;
} else {
strncpy(base_addr_str, peer_addr_str,
sizeof(base_addr_str) - 1);
}

addr_ok = net_ipaddr_parse(base_peer_addr,
strlen(base_peer_addr),
&remote_addr);

#if defined(CONFIG_NET_IPV6)
if (remote_addr.sa_family == AF_INET6) {
net_sin6(&remote_addr)->sin6_port = htons(peer_port);
}
#endif
#if defined(CONFIG_NET_IPV4)
if (remote_addr.sa_family == AF_INET) {
net_sin(&remote_addr)->sin_port = htons(peer_port);
}
#endif

/* The remote_addr will be used by set_remote_addr() to
* set the actual peer address.
*/
}

if (client_addr) {
memcpy(&addr, client_addr, sizeof(addr));

if (addr.sa_family != remote_addr.sa_family) {
NET_DBG("Address family mismatch %d vs %d",
addr.sa_family, remote_addr.sa_family);
return -EINVAL;
}
} else {
addr.sa_family = AF_UNSPEC;
addr.sa_family = remote_addr.sa_family;
}

ctx->app_type = NET_APP_CLIENT;
Expand All @@ -334,6 +363,7 @@ int net_app_init_client(struct net_app_ctx *ctx,

ret = _net_app_config_local_ctx(ctx, sock_type, proto, &addr);
if (ret < 0) {
close_net_ctx(ctx);
goto fail;
}

Expand Down Expand Up @@ -362,14 +392,26 @@ int net_app_init_client(struct net_app_ctx *ctx,
if (!peer_addr_str) {
NET_ERR("Cannot know where to connect.");
ret = -EINVAL;
close_net_ctx(ctx);
goto fail;
}

ret = set_remote_addr(ctx, peer_addr_str, peer_port, timeout);
ret = set_remote_addr(ctx, &remote_addr, base_addr_str,
addr_ok, timeout);
if (ret < 0) {
close_net_ctx(ctx);
goto fail;
}

/* If we have not yet figured out what is the protocol family,
* then we cannot continue.
*/
if (!ctx->default_ctx ||
ctx->default_ctx->remote.sa_family == AF_UNSPEC) {
NET_ERR("Unknown protocol family.");
return -EPFNOSUPPORT;
}

#if defined(CONFIG_NET_IPV4)
if (ctx->ipv4.remote.sa_family == AF_INET) {
ctx->ipv4.local.sa_family = AF_INET;
Expand Down
7 changes: 3 additions & 4 deletions subsys/net/lib/app/net_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,9 +852,6 @@ int net_app_close(struct net_app_ctx *ctx)
}

net_ctx = _net_app_select_net_ctx(ctx, NULL);
if (!net_ctx) {
return -EAFNOSUPPORT;
}

if (ctx->cb.close) {
ctx->cb.close(ctx, 0, ctx->user_data);
Expand All @@ -866,7 +863,9 @@ int net_app_close(struct net_app_ctx *ctx)
}
#endif

net_context_put(net_ctx);
if (net_ctx) {
net_context_put(net_ctx);
}

return 0;
}
Expand Down
4 changes: 4 additions & 0 deletions tests/net/app/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
BOARD ?= qemu_x86
CONF_FILE = prj.conf

include $(ZEPHYR_BASE)/Makefile.test
Loading