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