From fd792f93c406acfc965dcff3ce2f7e972938a373 Mon Sep 17 00:00:00 2001 From: Marcus Nilsson Date: Wed, 16 Aug 2023 22:48:42 +0200 Subject: [PATCH] LibC: Use gethostbyname_r() in gethostbyname() Since `gethostbyname()` can't fail because of memory-related issues, it has no way of representing a memory-related failure. We therefor use `NO_RECOVERY` to represent a memory-related failure as well as its normal name server related failures. --- Userland/Libraries/LibC/netdb.cpp | 123 +++++++----------------------- 1 file changed, 26 insertions(+), 97 deletions(-) diff --git a/Userland/Libraries/LibC/netdb.cpp b/Userland/Libraries/LibC/netdb.cpp index 3f3716e436..8e1fdf1ec8 100644 --- a/Userland/Libraries/LibC/netdb.cpp +++ b/Userland/Libraries/LibC/netdb.cpp @@ -93,108 +93,36 @@ static DeprecatedString gethostbyname_name_buffer; hostent* gethostbyname(char const* name) { - h_errno = 0; + struct hostent ret = {}; + struct hostent* result = nullptr; + size_t buffer_size = 1024; + char* buffer = nullptr; - auto ipv4_address = IPv4Address::from_string({ name, strlen(name) }); - - if (ipv4_address.has_value()) { - gethostbyname_name_buffer = ipv4_address.value().to_deprecated_string(); - __gethostbyname_buffer.h_name = const_cast(gethostbyname_name_buffer.characters()); - __gethostbyname_alias_list_buffer[0] = nullptr; - __gethostbyname_buffer.h_aliases = __gethostbyname_alias_list_buffer; - __gethostbyname_buffer.h_addrtype = AF_INET; - new (&__gethostbyname_address) IPv4Address(ipv4_address.value()); - __gethostbyname_address_list_buffer[0] = &__gethostbyname_address; - __gethostbyname_address_list_buffer[1] = nullptr; - __gethostbyname_buffer.h_addr_list = (char**)__gethostbyname_address_list_buffer; - __gethostbyname_buffer.h_length = 4; - - return &__gethostbyname_buffer; - } - - int fd = connect_to_lookup_server(); - if (fd < 0) { - h_errno = TRY_AGAIN; - return nullptr; - } - - auto close_fd_on_exit = ScopeGuard([fd] { - close(fd); + auto free_buffer_on_exit = ScopeGuard([buffer] { + if (buffer != nullptr) + free(buffer); }); - auto name_length = strlen(name); - VERIFY(name_length <= NumericLimits::max()); + while (true) { + buffer = (char*)realloc(buffer, buffer_size); + if (buffer == nullptr) { + // NOTE: Since gethostbyname usually can't fail because of memory, + // it has no way of representing OOM or allocation failure. + // NO_RECOVERY is the next best thing. + h_errno = NO_RECOVERY; + return NULL; + } - struct [[gnu::packed]] { - u32 message_size; - u32 endpoint_magic; - i32 message_id; - u32 name_length; - } request_header = { - (u32)(sizeof(request_header) - sizeof(request_header.message_size) + name_length), - lookup_server_endpoint_magic, - 1, - static_cast(name_length), - }; - if (auto nsent = write(fd, &request_header, sizeof(request_header)); nsent < 0) { - h_errno = TRY_AGAIN; - return nullptr; - } else if (nsent != sizeof(request_header)) { - h_errno = NO_RECOVERY; - return nullptr; - } + int rc = gethostbyname_r(name, &ret, buffer, buffer_size, &result, &h_errno); + if (rc == ERANGE) { + buffer_size *= 2; + continue; + } - if (auto nsent = write(fd, name, name_length); nsent < 0) { - h_errno = TRY_AGAIN; - return nullptr; - } else if (static_cast(nsent) != name_length) { - h_errno = NO_RECOVERY; - return nullptr; - } + if (rc < 0) + return nullptr; - struct [[gnu::packed]] { - u32 message_size; - u32 endpoint_magic; - i32 message_id; - i32 code; - u32 addresses_count; - } response_header; - - if (auto nreceived = read(fd, &response_header, sizeof(response_header)); nreceived < 0) { - h_errno = TRY_AGAIN; - return nullptr; - } else if (nreceived != sizeof(response_header)) { - h_errno = NO_RECOVERY; - return nullptr; - } - if (response_header.endpoint_magic != lookup_server_endpoint_magic || response_header.message_id != 2) { - h_errno = NO_RECOVERY; - return nullptr; - } - if (response_header.code != 0) { - h_errno = NO_RECOVERY; - return nullptr; - } - if (response_header.addresses_count == 0) { - h_errno = HOST_NOT_FOUND; - return nullptr; - } - i32 response_length; - if (auto nreceived = read(fd, &response_length, sizeof(response_length)); nreceived < 0) { - h_errno = TRY_AGAIN; - return nullptr; - } else if (nreceived != sizeof(response_length) - || response_length != sizeof(__gethostbyname_address)) { - h_errno = NO_RECOVERY; - return nullptr; - } - - if (auto nreceived = read(fd, &__gethostbyname_address, response_length); nreceived < 0) { - h_errno = TRY_AGAIN; - return nullptr; - } else if (nreceived != response_length) { - h_errno = NO_RECOVERY; - return nullptr; + break; } gethostbyname_name_buffer = name; @@ -202,10 +130,11 @@ hostent* gethostbyname(char const* name) __gethostbyname_alias_list_buffer[0] = nullptr; __gethostbyname_buffer.h_aliases = __gethostbyname_alias_list_buffer; __gethostbyname_buffer.h_addrtype = AF_INET; + memcpy(&__gethostbyname_address, result->h_addr_list[0], sizeof(in_addr_t)); __gethostbyname_address_list_buffer[0] = &__gethostbyname_address; __gethostbyname_address_list_buffer[1] = nullptr; __gethostbyname_buffer.h_addr_list = (char**)__gethostbyname_address_list_buffer; - __gethostbyname_buffer.h_length = 4; + __gethostbyname_buffer.h_length = result->h_length; return &__gethostbyname_buffer; }