Skip to content

Commit

Permalink
Merge pull request #707 from david-cermak/bugfix/sckutls_gethostname
Browse files Browse the repository at this point in the history
[sock-utils]: Add support for gethostname()
  • Loading branch information
david-cermak authored Dec 16, 2024
2 parents 54271a1 + f7c0b75 commit e12ecb8
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 0 deletions.
1 change: 1 addition & 0 deletions components/sock_utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ idf_component_register(SRCS "src/getnameinfo.c"
"src/ifaddrs.c"
"src/gai_strerror.c"
"src/socketpair.c"
"src/gethostname.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES lwip esp_netif)
1 change: 1 addition & 0 deletions components/sock_utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ This component provides simplified implementations of common socket-related util
| `pipe()` | Wraps `socketpair()` to provide unidirectional pipe-like functionality | Uses bidirectional sockets in place of true pipes |
| `getnameinfo()` | Converts IP addresses to human-readable form using `lwIP`'s `inet_ntop()` | IPv4 only; supports `NI_NUMERICHOST` and `NI_NUMERICSERV` flags only |
| `gai_strerror()` | Returns error code as a string | Simple numeric string representation only |
| `gethostname()` | Returns lwip netif hostname | Not a system-wide hostname, but interface specific hostname |

**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.
51 changes: 51 additions & 0 deletions components/sock_utils/include/gethostname.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once

#include <unistd.h>
#include "sdkconfig.h"

#ifdef CONFIG_IDF_TARGET_LINUX
// namespace with esp_ on linux to avoid conflict of symbols
#define gethostname esp_gethostname
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Retrieves the hostname of the device.
*
* This function provides the hostname associated with the network interface.
* Unlike the standard behavior where the hostname represents a system-wide name,
* this implementation returns lwip netif hostname (used as a hostname in DHCP packets)
*
* @param[out] name A pointer to a buffer where the hostname will be stored.
* The buffer must be allocated by the caller.
* @param[in] len The size of the buffer pointed to by @p name. The hostname,
* including the null-terminator, must fit within this size.
*
* @return
* - 0 on success
* - -1 on error, with `errno` set to indicate the error:
* - `EINVAL`: Invalid argument, name is NULL, or hostname is too long
*
* @note This implementation retrieves the hostname associated with the network
* interface using the `esp_netif_get_hostname()` function, which in turn
* returns lwip netif hostname used in DHCP packets if LWIP_NETIF_HOSTNAME=1 (hardcoded)
* in ESP-IDF lwip port.
* As there could be multiple network interfaces in the system, the logic tries
* to find the default (active) netif first, then it looks for any (inactive) netif
* with highest route priority. If none of the above found or esp_netif_get_hostname() fails
* for the selected interface, this API returns the default value of `CONFIG_LWIP_LOCAL_HOSTNAME`,
* the local hostname from lwip component configuration menu.
*/
int gethostname(char *name, size_t len);

#ifdef __cplusplus
}
#endif
46 changes: 46 additions & 0 deletions components/sock_utils/src/gethostname.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "gethostname.h"
#include "esp_netif.h"
#include "errno.h"
#include "esp_log.h"


static bool highest_prio_netif(esp_netif_t *netif, void *ctx)
{
esp_netif_t **highest_so_far = ctx;
if (esp_netif_get_route_prio(netif) > esp_netif_get_route_prio(*highest_so_far)) {
*highest_so_far = netif;
}
return false; // go over the entire list to find the netif with the highest route-prio
}

int gethostname(char *name, size_t len)
{
if (name == NULL) {
errno = EINVAL;
return -1;
}
const char *netif_hostname = CONFIG_LWIP_LOCAL_HOSTNAME; // default value from Kconfig

// Find the default netif
esp_netif_t *default_netif = esp_netif_get_default_netif();
if (default_netif == NULL) { // if no netif is active/up -> find the highest prio netif
esp_netif_find_if(highest_prio_netif, &default_netif);
}
// now the `default_netif` could be NULL and/or the esp_netif_get_hostname() could fail
// but we ignore the return code, as if it fails, the `netif_hostname` still holds the default value
esp_netif_get_hostname(default_netif, &netif_hostname);

size_t hostname_len;
if (netif_hostname == NULL || len < (hostname_len = strlen(netif_hostname) + 1)) { // including the NULL terminator
errno = EINVAL;
return -1;
}
memcpy(name, netif_hostname, hostname_len);
return 0;
}
25 changes: 25 additions & 0 deletions components/sock_utils/test/host/main/test_sock_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "gethostname.h"
#include "ifaddrs.h"
#include "esp_netif.h"
#include "esp_event.h"
Expand Down Expand Up @@ -148,6 +149,30 @@ TEST_CASE("gai_strerror()", "[sock_utils]")
CHECK(str_error != NULL);
}

TEST_CASE("gethostname()", "[sock_utils]")
{
const char *test_netif_name = "station";
char hostname[32];
int ret;

// expect failure
ret = gethostname(hostname, strlen(CONFIG_LWIP_LOCAL_HOSTNAME) - 1);
CHECK(ret == -1);

// happy flow with the default name
ret = gethostname(hostname, sizeof(hostname));
CHECK(ret == 0);
CHECK(strcmp(hostname, CONFIG_LWIP_LOCAL_HOSTNAME) == 0);

// happy flow with the netif name
esp_netif_t *esp_netif = create_test_netif(test_netif_name, 1);
REQUIRE(esp_netif != NULL);
CHECK(esp_netif_set_hostname(esp_netif, test_netif_name) == ESP_OK);
ret = gethostname(hostname, sizeof(hostname));
CHECK(ret == 0);
CHECK(strcmp(hostname, test_netif_name) == 0);
esp_netif_destroy(esp_netif);
}

extern "C" void app_main(void)
{
Expand Down

0 comments on commit e12ecb8

Please sign in to comment.