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 11*63ffcf69SJohn Baldwin #include <sys/nv.h> 1222ce7be7SJohn Baldwin #include <netdb.h> 13937e92b5SJohn Baldwin #include <unistd.h> 1422ce7be7SJohn Baldwin 15b3127a2dSJohn Baldwin #include <cstdarg> 16b3127a2dSJohn Baldwin #include <cstdio> 17b3127a2dSJohn Baldwin #include <cstdlib> 18b3127a2dSJohn Baldwin #include <memory> 19b3127a2dSJohn Baldwin 20b3127a2dSJohn Baldwin namespace freebsd { 21b3127a2dSJohn Baldwin /* 22b3127a2dSJohn Baldwin * FILE_up is a std::unique_ptr<> for FILE objects which uses 23b3127a2dSJohn Baldwin * fclose() to destroy the wrapped pointer. 24b3127a2dSJohn Baldwin */ 25b3127a2dSJohn Baldwin struct fclose_deleter { 26b3127a2dSJohn Baldwin void operator() (std::FILE *fp) const 27b3127a2dSJohn Baldwin { 28b3127a2dSJohn Baldwin std::fclose(fp); 29b3127a2dSJohn Baldwin } 30b3127a2dSJohn Baldwin }; 31b3127a2dSJohn Baldwin 32b3127a2dSJohn Baldwin using FILE_up = std::unique_ptr<std::FILE, fclose_deleter>; 33b3127a2dSJohn Baldwin 34b3127a2dSJohn Baldwin /* 3522ce7be7SJohn Baldwin * addrinfo_up is a std::unique_ptr<> which uses 3622ce7be7SJohn Baldwin * freeaddrinfo() to destroy the wrapped pointer. It is 3722ce7be7SJohn Baldwin * intended to wrap arrays allocated by getaddrinfo(). 3822ce7be7SJohn Baldwin */ 3922ce7be7SJohn Baldwin struct freeaddrinfo_deleter { 4022ce7be7SJohn Baldwin void operator() (struct addrinfo *ai) const 4122ce7be7SJohn Baldwin { 4222ce7be7SJohn Baldwin freeaddrinfo(ai); 4322ce7be7SJohn Baldwin } 4422ce7be7SJohn Baldwin }; 4522ce7be7SJohn Baldwin 4622ce7be7SJohn Baldwin using addrinfo_up = std::unique_ptr<addrinfo, freeaddrinfo_deleter>; 4722ce7be7SJohn Baldwin 4822ce7be7SJohn Baldwin /* 49937e92b5SJohn Baldwin * This class is intended to function similar to unique_ptr<>, 50937e92b5SJohn Baldwin * but it contains a file descriptor rather than a pointer to 51937e92b5SJohn Baldwin * an object. On destruction the descriptor is closed via 52937e92b5SJohn Baldwin * close(2). 53937e92b5SJohn Baldwin * 54937e92b5SJohn Baldwin * Similar to unique_ptr<>, release() returns ownership of the 55937e92b5SJohn Baldwin * file descriptor to the caller. reset() closes the current 56937e92b5SJohn Baldwin * file descriptor and takes ownership of a new one. A move 57937e92b5SJohn Baldwin * constructor permits ownership to be transferred via 58937e92b5SJohn Baldwin * std::move(). An integer file descriptor can be assigned 59937e92b5SJohn Baldwin * directly which is equivalent to calling reset(). 60937e92b5SJohn Baldwin * 61937e92b5SJohn Baldwin * An explicit bool conversion operator permits testing this 62937e92b5SJohn Baldwin * class in logical expressions. It returns true if it 63937e92b5SJohn Baldwin * contains a valid descriptor. 64937e92b5SJohn Baldwin * 65937e92b5SJohn Baldwin * An implicit int conversion operator returns the underlying 66937e92b5SJohn Baldwin * file descriptor allowing objects of this type to be passed 67937e92b5SJohn Baldwin * directly to APIs such as connect(), listen(), etc. 68937e92b5SJohn Baldwin */ 69937e92b5SJohn Baldwin class fd_up { 70937e92b5SJohn Baldwin public: 71937e92b5SJohn Baldwin fd_up() : fd(-1) {} 72937e92b5SJohn Baldwin fd_up(int fd) : fd(fd) {} 73937e92b5SJohn Baldwin fd_up(fd_up &&other) : fd(other.release()) {} 74937e92b5SJohn Baldwin fd_up(fd_up const &) = delete; 75937e92b5SJohn Baldwin 76937e92b5SJohn Baldwin ~fd_up() { reset(); } 77937e92b5SJohn Baldwin 78937e92b5SJohn Baldwin int get() const { return (fd); } 79937e92b5SJohn Baldwin 80937e92b5SJohn Baldwin int release() 81937e92b5SJohn Baldwin { 82937e92b5SJohn Baldwin int oldfd = fd; 83937e92b5SJohn Baldwin 84937e92b5SJohn Baldwin fd = -1; 85937e92b5SJohn Baldwin return (oldfd); 86937e92b5SJohn Baldwin } 87937e92b5SJohn Baldwin 88937e92b5SJohn Baldwin void reset(int newfd = -1) 89937e92b5SJohn Baldwin { 90937e92b5SJohn Baldwin if (fd >= 0) 91937e92b5SJohn Baldwin close(fd); 92937e92b5SJohn Baldwin fd = newfd; 93937e92b5SJohn Baldwin } 94937e92b5SJohn Baldwin 95937e92b5SJohn Baldwin fd_up &operator=(fd_up &&other) noexcept 96937e92b5SJohn Baldwin { 97937e92b5SJohn Baldwin if (this == &other) 98937e92b5SJohn Baldwin return *this; 99937e92b5SJohn Baldwin 100937e92b5SJohn Baldwin reset(other.release()); 101937e92b5SJohn Baldwin return *this; 102937e92b5SJohn Baldwin } 103937e92b5SJohn Baldwin 104937e92b5SJohn Baldwin fd_up &operator=(fd_up const &) = delete; 105937e92b5SJohn Baldwin 106937e92b5SJohn Baldwin fd_up &operator=(int newfd) 107937e92b5SJohn Baldwin { 108937e92b5SJohn Baldwin reset(newfd); 109937e92b5SJohn Baldwin return *this; 110937e92b5SJohn Baldwin } 111937e92b5SJohn Baldwin 112937e92b5SJohn Baldwin explicit operator bool() const { return fd >= 0; } 113937e92b5SJohn Baldwin operator int() const { return fd; } 114937e92b5SJohn Baldwin private: 115937e92b5SJohn Baldwin int fd; 116937e92b5SJohn Baldwin }; 117937e92b5SJohn Baldwin 118937e92b5SJohn Baldwin /* 119b3127a2dSJohn Baldwin * malloc_up<T> is a std::unique_ptr<> which uses free() to 120b3127a2dSJohn Baldwin * destroy the wrapped pointer. This can be used to wrap 121b3127a2dSJohn Baldwin * pointers allocated implicitly by malloc() such as those 122b3127a2dSJohn Baldwin * returned by strdup(). 123b3127a2dSJohn Baldwin */ 124b3127a2dSJohn Baldwin template <class T> 125b3127a2dSJohn Baldwin struct free_deleter { 126b3127a2dSJohn Baldwin void operator() (T *p) const 127b3127a2dSJohn Baldwin { 128b3127a2dSJohn Baldwin std::free(p); 129b3127a2dSJohn Baldwin } 130b3127a2dSJohn Baldwin }; 131b3127a2dSJohn Baldwin 132b3127a2dSJohn Baldwin template <class T> 133b3127a2dSJohn Baldwin using malloc_up = std::unique_ptr<T, free_deleter<T>>; 134b3127a2dSJohn Baldwin 135b3127a2dSJohn Baldwin /* 136*63ffcf69SJohn Baldwin * nvlist_up is a std::unique_ptr<> for nvlist_t objects which 137*63ffcf69SJohn Baldwin * uses nvlist_destroy() to destroy the wrapped pointer. 138*63ffcf69SJohn Baldwin */ 139*63ffcf69SJohn Baldwin struct nvlist_deleter { 140*63ffcf69SJohn Baldwin void operator() (nvlist_t *nvl) const 141*63ffcf69SJohn Baldwin { 142*63ffcf69SJohn Baldwin nvlist_destroy(nvl); 143*63ffcf69SJohn Baldwin } 144*63ffcf69SJohn Baldwin }; 145*63ffcf69SJohn Baldwin 146*63ffcf69SJohn Baldwin using nvlist_up = std::unique_ptr<nvlist_t, nvlist_deleter>; 147*63ffcf69SJohn Baldwin 148*63ffcf69SJohn Baldwin /* 149b3127a2dSJohn Baldwin * Returns a std::string containing the same output as 150b3127a2dSJohn Baldwin * sprintf(). Throws std::bad_alloc if an error occurs. 151b3127a2dSJohn Baldwin */ 152b3127a2dSJohn Baldwin std::string stringf(const char *fmt, ...) __printflike(1, 2); 153b3127a2dSJohn Baldwin std::string stringf(const char *fmt, std::va_list ap); 154b3127a2dSJohn Baldwin } 155b3127a2dSJohn Baldwin 156b3127a2dSJohn Baldwin #endif /* !__LIBUTILPP_HH__ */ 157