@@ -29,42 +29,74 @@ acceptor::acceptor(const std::string_view &sv)
2929 }
3030
3131 struct sockaddr_un addr {};
32+ std::size_t addr_size;
3233 addr.sun_family = AF_UNIX;
33- if (sv.size () > sizeof (addr.sun_path ) - 1 ) {
34- throw std::invalid_argument{" socket path too long" };
35- }
36- strcpy (static_cast <char *>(addr.sun_path ), sv.data ()); // NOLINT
34+ bool const is_abstract = (!sv.empty () && sv[0 ] == ' @' );
3735
38- // Remove the existing socket
39- int res = ::unlink (static_cast <char *>(addr.sun_path ));
40- if (res == -1 && errno != ENOENT) {
41- SPDLOG_ERROR (" Failed to unlink {}: errno {}" , addr.sun_path , errno);
42- throw std::system_error (errno, std::generic_category ());
36+ if (is_abstract) {
37+ #ifdef __linux__
38+ if (sv.size () > sizeof (addr.sun_path )) {
39+ throw std::invalid_argument{" socket path too long" };
40+ }
41+ // Replace @ with null byte for abstract namespace
42+ addr.sun_path [0 ] = ' \0 ' ;
43+ std::copy_n (sv.data () + 1 , sv.size () - 1 , &addr.sun_path [1 ]);
44+ addr_size = sv.size () + offsetof (struct sockaddr_un , sun_path);
45+ #else
46+ throw std::runtime_error{
47+ " Abstract namespace sockets are only supported on Linux" };
48+ #endif
49+ } else {
50+ // Filesystem socket
51+ if (sv.size () > sizeof (addr.sun_path ) - 1 ) {
52+ throw std::invalid_argument{" socket path too long" };
53+ }
54+ std::copy_n (sv.data (), sv.size (), &addr.sun_path [0 ]);
55+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
56+ addr.sun_path [sv.size ()] = ' \0 ' ;
57+ addr_size = sizeof (addr);
58+
59+ // Remove the existing socket
60+ int const res = ::unlink (static_cast <char *>(addr.sun_path ));
61+ if (res == -1 && errno != ENOENT) {
62+ SPDLOG_ERROR (" Failed to unlink {}: errno {}" , addr.sun_path , errno);
63+ throw std::system_error (errno, std::generic_category ());
64+ }
65+ SPDLOG_DEBUG (" Unlinked {}" , addr.sun_path );
4366 }
44- SPDLOG_DEBUG (" Unlinked {}" , addr.sun_path );
4567
46- res =
68+ int res = :: bind (
4769 // NOLINTNEXTLINE
48- ::bind (sock_.get(), reinterpret_cast<struct sockaddr *>(&addr),
49- sizeof(addr));
70+ sock_.get (), reinterpret_cast <struct sockaddr *>(&addr), addr_size);
5071 if (res == -1 ) {
51- SPDLOG_ERROR (
52- " Failed to bind socket to {}: errno {}" , addr.sun_path , errno);
72+ if (is_abstract) {
73+ SPDLOG_ERROR (" Failed to bind abstract socket: errno {}" , errno);
74+ } else {
75+ SPDLOG_ERROR (
76+ " Failed to bind socket to {}: errno {}" , addr.sun_path , errno);
77+ }
5378 throw std::system_error (errno, std::generic_category ());
5479 }
5580
56- res = ::chmod (sv.data (), 0777 ); // NOLINT
57- if (res == -1 ) {
58- SPDLOG_ERROR (
59- " Failed to chmod socket {}: errno {}" , addr.sun_path , errno);
60- throw std::system_error (errno, std::generic_category ());
81+ if (!is_abstract) {
82+ res = ::chmod (sv.data (), 0777 ); // NOLINT
83+ if (res == -1 ) {
84+ SPDLOG_ERROR (
85+ " Failed to chmod socket {}: errno {}" , addr.sun_path , errno);
86+ throw std::system_error (errno, std::generic_category ());
87+ }
6188 }
6289
6390 static constexpr int backlog = 50 ;
6491 if (::listen (sock_.get (), backlog) == -1 ) {
6592 throw std::system_error (errno, std::generic_category ());
6693 }
67- SPDLOG_INFO (" Started listening on {}" , sv);
94+
95+ if (is_abstract) {
96+ SPDLOG_INFO (" Started listening on abstract socket: {}" , sv);
97+ } else {
98+ SPDLOG_INFO (" Started listening on {}" , sv);
99+ }
68100}
69101
70102void acceptor::set_accept_timeout (std::chrono::seconds timeout)
0 commit comments