From ccf9acc6cf2310f83ea7106718ccd45edbc3e96d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 7 May 2019 20:16:07 +0300 Subject: [PATCH 1/3] net: socket: Define NI_MAXHOST for compatibility Not in POSIX. Linux man getnameinfo says about it: "In order to assist the programmer in choosing reasonable sizes for the supplied buffers, defines the constants #define NI_MAXHOST 1025 #define NI_MAXSERV 32 Since glibc 2.8, these definitions are exposed only if suitable feature test macros are defined, namely: _GNU_SOURCE, _DEFAULT_SOURCE (since glibc 2.19), or (in glibc versions up to and including 2.19) _BSD_SOURCE or _SVID_SOURCE." Signed-off-by: Paul Sokolovsky --- include/net/socket.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/net/socket.h b/include/net/socket.h index 1cebc8073645b..34ba0245bf7c5 100644 --- a/include/net/socket.h +++ b/include/net/socket.h @@ -498,6 +498,13 @@ const char *zsock_gai_strerror(int errcode); /** zsock_getnameinfo(): Dummy option for compatibility */ #define NI_DGRAM 16 +/* POSIX extensions */ + +/** zsock_getnameinfo(): Max supported hostname length */ +#ifndef NI_MAXHOST +#define NI_MAXHOST 64 +#endif + /** * @brief Resolve a network address to a domain name or ASCII address * From ff17f484d22d47210a8ae96505008240b0319b1e Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 22 Apr 2019 17:26:45 +0300 Subject: [PATCH 2/3] net: socketutils: Add utils to manipulate network address strings Two utils to manipulate addresses in format "addr[:port]". I.e., network address (domain name or numeric), optionally followed by port number: * net_addr_str_find_port(), to return pointer to port number substring (or NULL if not present). * net_getaddrinfo_addr_str(), which is effectively getaddrinfo() wrapper taking a "addr[:port]" string as a parameter. The header file is named socketutils.h to emphasize that these utility functions are implemented on top of BSD Sockets API (and other POSIX/ANSI C functions), and thus portable to other POSIX systems (e.g., Linux), so can be used in apps testing POSIX compatibility. More utility functions (beyond address manipulation) can be added later. Signed-off-by: Paul Sokolovsky --- include/net/socketutils.h | 33 ++++++++++++++ subsys/net/lib/CMakeLists.txt | 1 + subsys/net/lib/utils/CMakeLists.txt | 5 +++ subsys/net/lib/utils/addr_utils.c | 67 +++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 include/net/socketutils.h create mode 100644 subsys/net/lib/utils/CMakeLists.txt create mode 100644 subsys/net/lib/utils/addr_utils.c diff --git a/include/net/socketutils.h b/include/net/socketutils.h new file mode 100644 index 0000000000000..8c2d815577698 --- /dev/null +++ b/include/net/socketutils.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Find port in addr:port string. + * + * @param addr_str String of addr[:port] format + * + * @return Pointer to "port" part, or NULL is none. + */ +const char *net_addr_str_find_port(const char *addr_str); + +/** + * @brief Call getaddrinfo() on addr:port string + * + * Convenience function to split addr[:port] string into address vs port + * components (or use default port number), and call getaddrinfo() on the + * result. + * + * @param addr_str String of addr[:port] format + * @param def_port Default port number to use if addr_str doesn't contain it + * @param hints getaddrinfo() hints + * @param res Result of getaddrinfo() (freeaddrinfo() should be called on it + * as usual. + * + * @return Result of getaddrinfo() call. + */ +int net_getaddrinfo_addr_str(const char *addr_str, const char *def_port, + const struct addrinfo *hints, + struct addrinfo **res); diff --git a/subsys/net/lib/CMakeLists.txt b/subsys/net/lib/CMakeLists.txt index 76e3c3754dbed..8a27019824346 100644 --- a/subsys/net/lib/CMakeLists.txt +++ b/subsys/net/lib/CMakeLists.txt @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 +add_subdirectory(utils) add_subdirectory_if_kconfig(coap) add_subdirectory_if_kconfig(lwm2m) add_subdirectory_if_kconfig(socks) diff --git a/subsys/net/lib/utils/CMakeLists.txt b/subsys/net/lib/utils/CMakeLists.txt new file mode 100644 index 0000000000000..dad9f2b5146b2 --- /dev/null +++ b/subsys/net/lib/utils/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + addr_utils.c +) diff --git a/subsys/net/lib/utils/addr_utils.c b/subsys/net/lib/utils/addr_utils.c new file mode 100644 index 0000000000000..8080c9dd9024d --- /dev/null +++ b/subsys/net/lib/utils/addr_utils.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* These utility functions are intended to be on top of POSIX API, and don't + * make sense if it's not available. + */ +#ifdef CONFIG_NET_SOCKETS_POSIX_NAMES + +const char *net_addr_str_find_port(const char *addr_str) +{ + const char *p = strrchr(addr_str, ':'); + + if (p == NULL) { + return NULL; + } + + /* If it's not IPv6 numeric notation, we guaranteedly got a port */ + if (*addr_str != '[') { + return p + 1; + } + + /* IPv6 numeric address, and ':' preceeded by ']' */ + if (p[-1] == ']') { + return p + 1; + } + + /* Otherwise, just raw IPv6 address, ':' is component separator */ + return NULL; +} + +int net_getaddrinfo_addr_str(const char *addr_str, const char *def_port, + const struct addrinfo *hints, + struct addrinfo **res) +{ + const char *port; + char host[NI_MAXHOST]; + + if (addr_str == NULL) { + errno = EINVAL; + return -1; + } + + port = net_addr_str_find_port(addr_str); + + if (port == NULL) { + port = def_port; + } else { + int host_len = port - addr_str - 1; + + if (host_len > sizeof(host) - 1) { + errno = EINVAL; + return -1; + } + strncpy(host, addr_str, host_len + 1); + host[host_len] = '\0'; + addr_str = host; + } + + return getaddrinfo(addr_str, port, hints, res); +} + +#endif From 6ad87865ea3356806cfab90afd9d1358bc55e392 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 22 Apr 2019 17:49:25 +0300 Subject: [PATCH 3/3] net: sntp: Add convenience API for one-shot SNTP query sntp_simple() function queries the server (passed as "addr[:port]" string). It wraps calls to a number of other functions, and may be useful to write simple, concise apps needing the absolute time. Signed-off-by: Paul Sokolovsky --- include/net/sntp.h | 16 +++++++++++ subsys/net/lib/sntp/CMakeLists.txt | 1 + subsys/net/lib/sntp/sntp_simple.c | 45 ++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 subsys/net/lib/sntp/sntp_simple.c diff --git a/include/net/sntp.h b/include/net/sntp.h index da950b561b2a6..eeaaf81949781 100644 --- a/include/net/sntp.h +++ b/include/net/sntp.h @@ -82,6 +82,22 @@ int sntp_query(struct sntp_ctx *ctx, u32_t timeout, */ void sntp_close(struct sntp_ctx *ctx); +/** + * @brief Convenience function to query SNTP in one-shot fashion + * + * Convenience wrapper which calls getaddrinfo(), sntp_init(), + * sntp_query(), and sntp_close(). + * + * @param server Address of server in format addr[:port] + * @param timeout Query timeout + * @param time Timestamp including integer and fractional seconds since + * 1 Jan 1970 (output). + * + * @return 0 if ok, <0 if error (-ETIMEDOUT if timeout). + */ +int sntp_simple(const char *server, u32_t timeout, + struct sntp_time *time); + /** * @} */ diff --git a/subsys/net/lib/sntp/CMakeLists.txt b/subsys/net/lib/sntp/CMakeLists.txt index 5ffac40aba7e0..e6f1b181699a1 100644 --- a/subsys/net/lib/sntp/CMakeLists.txt +++ b/subsys/net/lib/sntp/CMakeLists.txt @@ -2,4 +2,5 @@ zephyr_sources( sntp.c + sntp_simple.c ) diff --git a/subsys/net/lib/sntp/sntp_simple.c b/subsys/net/lib/sntp/sntp_simple.c new file mode 100644 index 0000000000000..36aab49dd4204 --- /dev/null +++ b/subsys/net/lib/sntp/sntp_simple.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include +#include + +int sntp_simple(const char *server, u32_t timeout, struct sntp_time *time) +{ + int res; + static struct addrinfo hints; + struct addrinfo *addr; + struct sntp_ctx sntp_ctx; + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = 0; + /* 123 is the standard SNTP port per RFC4330 */ + res = net_getaddrinfo_addr_str(server, "123", &hints, &addr); + + if (res < 0) { + /* Just in case, as namespace for getaddrinfo errors is + * different from errno errors. + */ + errno = EDOM; + return res; + } + + res = sntp_init(&sntp_ctx, addr->ai_addr, addr->ai_addrlen); + if (res < 0) { + goto freeaddr; + } + + res = sntp_query(&sntp_ctx, timeout, time); + + sntp_close(&sntp_ctx); + +freeaddr: + freeaddrinfo(addr); + + return res; +}