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