1b3127a2dSJohn Baldwin /*- 2b3127a2dSJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause 3b3127a2dSJohn Baldwin * 4b3127a2dSJohn Baldwin * Copyright (c) 2025 Chelsio Communications, Inc. 5b3127a2dSJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org> 6b3127a2dSJohn Baldwin */ 7b3127a2dSJohn Baldwin 8b3127a2dSJohn Baldwin #ifndef __LIBUTILPP_HH__ 9b3127a2dSJohn Baldwin #define __LIBUTILPP_HH__ 10b3127a2dSJohn Baldwin 1122ce7be7SJohn Baldwin #include <netdb.h> 12*937e92b5SJohn Baldwin #include <unistd.h> 1322ce7be7SJohn Baldwin 14b3127a2dSJohn Baldwin #include <cstdarg> 15b3127a2dSJohn Baldwin #include <cstdio> 16b3127a2dSJohn Baldwin #include <cstdlib> 17b3127a2dSJohn Baldwin #include <memory> 18b3127a2dSJohn Baldwin 19b3127a2dSJohn Baldwin namespace freebsd { 20b3127a2dSJohn Baldwin /* 21b3127a2dSJohn Baldwin * FILE_up is a std::unique_ptr<> for FILE objects which uses 22b3127a2dSJohn Baldwin * fclose() to destroy the wrapped pointer. 23b3127a2dSJohn Baldwin */ 24b3127a2dSJohn Baldwin struct fclose_deleter { 25b3127a2dSJohn Baldwin void operator() (std::FILE *fp) const 26b3127a2dSJohn Baldwin { 27b3127a2dSJohn Baldwin std::fclose(fp); 28b3127a2dSJohn Baldwin } 29b3127a2dSJohn Baldwin }; 30b3127a2dSJohn Baldwin 31b3127a2dSJohn Baldwin using FILE_up = std::unique_ptr<std::FILE, fclose_deleter>; 32b3127a2dSJohn Baldwin 33b3127a2dSJohn Baldwin /* 3422ce7be7SJohn Baldwin * addrinfo_up is a std::unique_ptr<> which uses 3522ce7be7SJohn Baldwin * freeaddrinfo() to destroy the wrapped pointer. It is 3622ce7be7SJohn Baldwin * intended to wrap arrays allocated by getaddrinfo(). 3722ce7be7SJohn Baldwin */ 3822ce7be7SJohn Baldwin struct freeaddrinfo_deleter { 3922ce7be7SJohn Baldwin void operator() (struct addrinfo *ai) const 4022ce7be7SJohn Baldwin { 4122ce7be7SJohn Baldwin freeaddrinfo(ai); 4222ce7be7SJohn Baldwin } 4322ce7be7SJohn Baldwin }; 4422ce7be7SJohn Baldwin 4522ce7be7SJohn Baldwin using addrinfo_up = std::unique_ptr<addrinfo, freeaddrinfo_deleter>; 4622ce7be7SJohn Baldwin 4722ce7be7SJohn Baldwin /* 48*937e92b5SJohn Baldwin * This class is intended to function similar to unique_ptr<>, 49*937e92b5SJohn Baldwin * but it contains a file descriptor rather than a pointer to 50*937e92b5SJohn Baldwin * an object. On destruction the descriptor is closed via 51*937e92b5SJohn Baldwin * close(2). 52*937e92b5SJohn Baldwin * 53*937e92b5SJohn Baldwin * Similar to unique_ptr<>, release() returns ownership of the 54*937e92b5SJohn Baldwin * file descriptor to the caller. reset() closes the current 55*937e92b5SJohn Baldwin * file descriptor and takes ownership of a new one. A move 56*937e92b5SJohn Baldwin * constructor permits ownership to be transferred via 57*937e92b5SJohn Baldwin * std::move(). An integer file descriptor can be assigned 58*937e92b5SJohn Baldwin * directly which is equivalent to calling reset(). 59*937e92b5SJohn Baldwin * 60*937e92b5SJohn Baldwin * An explicit bool conversion operator permits testing this 61*937e92b5SJohn Baldwin * class in logical expressions. It returns true if it 62*937e92b5SJohn Baldwin * contains a valid descriptor. 63*937e92b5SJohn Baldwin * 64*937e92b5SJohn Baldwin * An implicit int conversion operator returns the underlying 65*937e92b5SJohn Baldwin * file descriptor allowing objects of this type to be passed 66*937e92b5SJohn Baldwin * directly to APIs such as connect(), listen(), etc. 67*937e92b5SJohn Baldwin */ 68*937e92b5SJohn Baldwin class fd_up { 69*937e92b5SJohn Baldwin public: 70*937e92b5SJohn Baldwin fd_up() : fd(-1) {} 71*937e92b5SJohn Baldwin fd_up(int fd) : fd(fd) {} 72*937e92b5SJohn Baldwin fd_up(fd_up &&other) : fd(other.release()) {} 73*937e92b5SJohn Baldwin fd_up(fd_up const &) = delete; 74*937e92b5SJohn Baldwin 75*937e92b5SJohn Baldwin ~fd_up() { reset(); } 76*937e92b5SJohn Baldwin 77*937e92b5SJohn Baldwin int get() const { return (fd); } 78*937e92b5SJohn Baldwin 79*937e92b5SJohn Baldwin int release() 80*937e92b5SJohn Baldwin { 81*937e92b5SJohn Baldwin int oldfd = fd; 82*937e92b5SJohn Baldwin 83*937e92b5SJohn Baldwin fd = -1; 84*937e92b5SJohn Baldwin return (oldfd); 85*937e92b5SJohn Baldwin } 86*937e92b5SJohn Baldwin 87*937e92b5SJohn Baldwin void reset(int newfd = -1) 88*937e92b5SJohn Baldwin { 89*937e92b5SJohn Baldwin if (fd >= 0) 90*937e92b5SJohn Baldwin close(fd); 91*937e92b5SJohn Baldwin fd = newfd; 92*937e92b5SJohn Baldwin } 93*937e92b5SJohn Baldwin 94*937e92b5SJohn Baldwin fd_up &operator=(fd_up &&other) noexcept 95*937e92b5SJohn Baldwin { 96*937e92b5SJohn Baldwin if (this == &other) 97*937e92b5SJohn Baldwin return *this; 98*937e92b5SJohn Baldwin 99*937e92b5SJohn Baldwin reset(other.release()); 100*937e92b5SJohn Baldwin return *this; 101*937e92b5SJohn Baldwin } 102*937e92b5SJohn Baldwin 103*937e92b5SJohn Baldwin fd_up &operator=(fd_up const &) = delete; 104*937e92b5SJohn Baldwin 105*937e92b5SJohn Baldwin fd_up &operator=(int newfd) 106*937e92b5SJohn Baldwin { 107*937e92b5SJohn Baldwin reset(newfd); 108*937e92b5SJohn Baldwin return *this; 109*937e92b5SJohn Baldwin } 110*937e92b5SJohn Baldwin 111*937e92b5SJohn Baldwin explicit operator bool() const { return fd >= 0; } 112*937e92b5SJohn Baldwin operator int() const { return fd; } 113*937e92b5SJohn Baldwin private: 114*937e92b5SJohn Baldwin int fd; 115*937e92b5SJohn Baldwin }; 116*937e92b5SJohn Baldwin 117*937e92b5SJohn Baldwin /* 118b3127a2dSJohn Baldwin * malloc_up<T> is a std::unique_ptr<> which uses free() to 119b3127a2dSJohn Baldwin * destroy the wrapped pointer. This can be used to wrap 120b3127a2dSJohn Baldwin * pointers allocated implicitly by malloc() such as those 121b3127a2dSJohn Baldwin * returned by strdup(). 122b3127a2dSJohn Baldwin */ 123b3127a2dSJohn Baldwin template <class T> 124b3127a2dSJohn Baldwin struct free_deleter { 125b3127a2dSJohn Baldwin void operator() (T *p) const 126b3127a2dSJohn Baldwin { 127b3127a2dSJohn Baldwin std::free(p); 128b3127a2dSJohn Baldwin } 129b3127a2dSJohn Baldwin }; 130b3127a2dSJohn Baldwin 131b3127a2dSJohn Baldwin template <class T> 132b3127a2dSJohn Baldwin using malloc_up = std::unique_ptr<T, free_deleter<T>>; 133b3127a2dSJohn Baldwin 134b3127a2dSJohn Baldwin /* 135b3127a2dSJohn Baldwin * Returns a std::string containing the same output as 136b3127a2dSJohn Baldwin * sprintf(). Throws std::bad_alloc if an error occurs. 137b3127a2dSJohn Baldwin */ 138b3127a2dSJohn Baldwin std::string stringf(const char *fmt, ...) __printflike(1, 2); 139b3127a2dSJohn Baldwin std::string stringf(const char *fmt, std::va_list ap); 140b3127a2dSJohn Baldwin } 141b3127a2dSJohn Baldwin 142b3127a2dSJohn Baldwin #endif /* !__LIBUTILPP_HH__ */ 143