Skip to content

Commit f7c0b75

Browse files
committed
feat(sockutls): Add support for gethostname()
Closes espressif/esp-idf#14849
1 parent 32387f7 commit f7c0b75

File tree

5 files changed

+124
-0
lines changed

5 files changed

+124
-0
lines changed

components/sock_utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ idf_component_register(SRCS "src/getnameinfo.c"
22
"src/ifaddrs.c"
33
"src/gai_strerror.c"
44
"src/socketpair.c"
5+
"src/gethostname.c"
56
INCLUDE_DIRS "include"
67
PRIV_REQUIRES lwip esp_netif)

components/sock_utils/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ This component provides simplified implementations of common socket-related util
1313
| `pipe()` | Wraps `socketpair()` to provide unidirectional pipe-like functionality | Uses bidirectional sockets in place of true pipes |
1414
| `getnameinfo()` | Converts IP addresses to human-readable form using `lwIP`'s `inet_ntop()` | IPv4 only; supports `NI_NUMERICHOST` and `NI_NUMERICSERV` flags only |
1515
| `gai_strerror()` | Returns error code as a string | Simple numeric string representation only |
16+
| `gethostname()` | Returns lwip netif hostname | Not a system-wide hostname, but interface specific hostname |
1617

1718
**Note**: `socketpair()` and `pipe()` are built on top of `lwIP` TCP sockets, inheriting the same characteristics. For instance, the maximum transmit buffer size is based on the `TCP_SND_BUF` setting.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#pragma once
7+
8+
#include <unistd.h>
9+
#include "sdkconfig.h"
10+
11+
#ifdef CONFIG_IDF_TARGET_LINUX
12+
// namespace with esp_ on linux to avoid conflict of symbols
13+
#define gethostname esp_gethostname
14+
#endif
15+
16+
#ifdef __cplusplus
17+
extern "C" {
18+
#endif
19+
20+
/**
21+
* @brief Retrieves the hostname of the device.
22+
*
23+
* This function provides the hostname associated with the network interface.
24+
* Unlike the standard behavior where the hostname represents a system-wide name,
25+
* this implementation returns lwip netif hostname (used as a hostname in DHCP packets)
26+
*
27+
* @param[out] name A pointer to a buffer where the hostname will be stored.
28+
* The buffer must be allocated by the caller.
29+
* @param[in] len The size of the buffer pointed to by @p name. The hostname,
30+
* including the null-terminator, must fit within this size.
31+
*
32+
* @return
33+
* - 0 on success
34+
* - -1 on error, with `errno` set to indicate the error:
35+
* - `EINVAL`: Invalid argument, name is NULL, or hostname is too long
36+
*
37+
* @note This implementation retrieves the hostname associated with the network
38+
* interface using the `esp_netif_get_hostname()` function, which in turn
39+
* returns lwip netif hostname used in DHCP packets if LWIP_NETIF_HOSTNAME=1 (hardcoded)
40+
* in ESP-IDF lwip port.
41+
* As there could be multiple network interfaces in the system, the logic tries
42+
* to find the default (active) netif first, then it looks for any (inactive) netif
43+
* with highest route priority. If none of the above found or esp_netif_get_hostname() fails
44+
* for the selected interface, this API returns the default value of `CONFIG_LWIP_LOCAL_HOSTNAME`,
45+
* the local hostname from lwip component configuration menu.
46+
*/
47+
int gethostname(char *name, size_t len);
48+
49+
#ifdef __cplusplus
50+
}
51+
#endif
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <string.h>
7+
#include "gethostname.h"
8+
#include "esp_netif.h"
9+
#include "errno.h"
10+
#include "esp_log.h"
11+
12+
13+
static bool highest_prio_netif(esp_netif_t *netif, void *ctx)
14+
{
15+
esp_netif_t **highest_so_far = ctx;
16+
if (esp_netif_get_route_prio(netif) > esp_netif_get_route_prio(*highest_so_far)) {
17+
*highest_so_far = netif;
18+
}
19+
return false; // go over the entire list to find the netif with the highest route-prio
20+
}
21+
22+
int gethostname(char *name, size_t len)
23+
{
24+
if (name == NULL) {
25+
errno = EINVAL;
26+
return -1;
27+
}
28+
const char *netif_hostname = CONFIG_LWIP_LOCAL_HOSTNAME; // default value from Kconfig
29+
30+
// Find the default netif
31+
esp_netif_t *default_netif = esp_netif_get_default_netif();
32+
if (default_netif == NULL) { // if no netif is active/up -> find the highest prio netif
33+
esp_netif_find_if(highest_prio_netif, &default_netif);
34+
}
35+
// now the `default_netif` could be NULL and/or the esp_netif_get_hostname() could fail
36+
// but we ignore the return code, as if it fails, the `netif_hostname` still holds the default value
37+
esp_netif_get_hostname(default_netif, &netif_hostname);
38+
39+
size_t hostname_len;
40+
if (netif_hostname == NULL || len < (hostname_len = strlen(netif_hostname) + 1)) { // including the NULL terminator
41+
errno = EINVAL;
42+
return -1;
43+
}
44+
memcpy(name, netif_hostname, hostname_len);
45+
return 0;
46+
}

components/sock_utils/test/host/main/test_sock_utils.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
6+
#include "gethostname.h"
67
#include "ifaddrs.h"
78
#include "esp_netif.h"
89
#include "esp_event.h"
@@ -148,6 +149,30 @@ TEST_CASE("gai_strerror()", "[sock_utils]")
148149
CHECK(str_error != NULL);
149150
}
150151

152+
TEST_CASE("gethostname()", "[sock_utils]")
153+
{
154+
const char *test_netif_name = "station";
155+
char hostname[32];
156+
int ret;
157+
158+
// expect failure
159+
ret = gethostname(hostname, strlen(CONFIG_LWIP_LOCAL_HOSTNAME) - 1);
160+
CHECK(ret == -1);
161+
162+
// happy flow with the default name
163+
ret = gethostname(hostname, sizeof(hostname));
164+
CHECK(ret == 0);
165+
CHECK(strcmp(hostname, CONFIG_LWIP_LOCAL_HOSTNAME) == 0);
166+
167+
// happy flow with the netif name
168+
esp_netif_t *esp_netif = create_test_netif(test_netif_name, 1);
169+
REQUIRE(esp_netif != NULL);
170+
CHECK(esp_netif_set_hostname(esp_netif, test_netif_name) == ESP_OK);
171+
ret = gethostname(hostname, sizeof(hostname));
172+
CHECK(ret == 0);
173+
CHECK(strcmp(hostname, test_netif_name) == 0);
174+
esp_netif_destroy(esp_netif);
175+
}
151176

152177
extern "C" void app_main(void)
153178
{

0 commit comments

Comments
 (0)