blob: c63861d4031dfa5e3b0fa3acbf24b55002040707 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/base/sockaddr_util_posix.h"
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "base/containers/span.h"
#include "base/strings/string_view_util.h"
#include "net/base/sockaddr_storage.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
namespace {
// The largest possible platform-dependent value. Subtracting one for an extra
// NUL character at the front or back.
constexpr size_t kMaxUnixAddressPath = sizeof(sockaddr_un::sun_path) - 1;
} // namespace
TEST(FillUnixAddressTest, SimpleAddress) {
SockaddrStorage storage;
std::string path = "/tmp/socket/path";
EXPECT_TRUE(
FillUnixAddress(path, /*use_abstract_namespace=*/false, &storage));
// |storage.addr_len| indicates the full size of the data in sockaddr_un.
// The size is increased by one byte to include the string NUL terminator.
EXPECT_EQ(path.size() + 1U + offsetof(struct sockaddr_un, sun_path),
(unsigned int)storage.addr_len);
struct sockaddr_un* socket_addr =
reinterpret_cast<struct sockaddr_un*>(&storage.addr_storage);
EXPECT_EQ(socket_addr->sun_family, AF_UNIX);
// Implicit conversion to std::string for comparison is fine since the path
// is always NUL terminated.
EXPECT_EQ(socket_addr->sun_path, path);
}
TEST(FillUnixAddressTest, PathEmpty) {
SockaddrStorage storage;
std::string path = "";
EXPECT_FALSE(
FillUnixAddress(path, /*use_abstract_namespace=*/false, &storage));
}
TEST(FillUnixAddressTest, AddressMaxLength) {
SockaddrStorage storage;
std::string path(kMaxUnixAddressPath, '0');
EXPECT_TRUE(
FillUnixAddress(path, /*use_abstract_namespace=*/false, &storage));
struct sockaddr_un* socket_addr =
reinterpret_cast<struct sockaddr_un*>(&storage.addr_storage);
EXPECT_EQ(socket_addr->sun_family, AF_UNIX);
EXPECT_EQ(socket_addr->sun_path, path);
}
TEST(FillUnixAddressTest, AddressTooLong) {
SockaddrStorage storage;
std::string path(kMaxUnixAddressPath + 1, '0');
EXPECT_FALSE(
FillUnixAddress(path, /*use_abstract_namespace=*/false, &storage));
}
TEST(FillUnixAddressTest, AbstractLinuxAddress) {
SockaddrStorage storage;
std::string path(kMaxUnixAddressPath, '0');
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
EXPECT_TRUE(FillUnixAddress(path, /*use_abstract_namespace=*/true, &storage));
EXPECT_EQ(path.size() + 1U + offsetof(struct sockaddr_un, sun_path),
static_cast<size_t>(storage.addr_len));
struct sockaddr_un* socket_addr =
reinterpret_cast<struct sockaddr_un*>(&storage.addr_storage);
EXPECT_EQ(socket_addr->sun_family, AF_UNIX);
// The path buffer is preceded by a NUL character for abstract Linux
// addresses.
EXPECT_EQ(socket_addr->sun_path[0], '\0');
// The rest of the path. Note that `addr_len` has already been verified to be
// correct, so only need to check the remaining path.size() characters of the
// address struct, after the nul. Create a span and then a string_view from it
// because span's constructor creates a span from the length of the array
// that's passed in, while string_view's constructor will treat the input as
// C-string and look for the terminating null at the end, and abstract Linux
// paths are not guaranteed to be null terminated when in a `sockaddr_un`.
std::string_view unix_path = base::as_string_view(
base::span(socket_addr->sun_path).subspan(1u, path.size()));
EXPECT_EQ(unix_path, path);
#else
// Other platforms don't support the abstract Linux namespace.
EXPECT_FALSE(
FillUnixAddress(path, /*use_abstract_namespace=*/true, &storage));
#endif
}
} // namespace net