General Purpose library for Freestanding C++ and POSIX systems
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
5.7 KiB

5 년 전
5 년 전
  1. #pragma once
  2. #include <fcntl.h>
  3. #include <unistd.h>
  4. #include <sys/mman.h>
  5. #include <sys/stat.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <sys/un.h>
  10. #include <string>
  11. #include <sstream>
  12. #include <atomic>
  13. #include <array>
  14. #include <variant>
  15. #include <cassert>
  16. namespace gp{
  17. using open_opt_flags = int;
  18. enum class open_options : open_opt_flags {
  19. append = O_APPEND,
  20. create = O_CREAT,
  21. async = O_ASYNC,
  22. direct = O_DIRECT,
  23. data_sync = O_DSYNC,
  24. file_sync = O_SYNC,
  25. exclusive = O_EXCL,
  26. no_access_time = O_NOATIME,
  27. no_follow = O_NOFOLLOW,
  28. read = O_RDONLY,
  29. write = O_WRONLY,
  30. #ifdef O_TEMP
  31. temporary = O_TEMP,
  32. #endif
  33. #ifdef O_TRUC
  34. truncate = O_TRUC,
  35. #endif
  36. };
  37. using open_opt_mode = int;
  38. enum class open_modes : open_opt_mode {
  39. user_read = S_IRUSR,
  40. user_write = S_IWUSR,
  41. user_exec = S_IXUSR,
  42. group_read = S_IRGRP,
  43. group_write = S_IWGRP,
  44. group_exec = S_IXGRP,
  45. other_read = S_IROTH,
  46. other_write = S_IWOTH,
  47. other_exec = S_IXOTH,
  48. set_uid = S_ISUID,
  49. set_gid = S_ISGID,
  50. sticky_bit = S_ISVTX,
  51. };
  52. enum class socket_domain : int {
  53. ip4 = AF_INET,
  54. ip6 = AF_INET6,
  55. unix = AF_UNIX
  56. };
  57. enum class socket_protocol : int {
  58. tcp_like = SOCK_STREAM,
  59. udp_like = SOCK_DGRAM
  60. };
  61. using socket_opt_flags = int;
  62. enum class net_socket_opt_flags : socket_opt_flags {
  63. non_blocking = SOCK_NONBLOCK,
  64. close_on_exec = SOCK_CLOEXEC,
  65. };
  66. using socket_opt_flags = int;
  67. enum class unix_socket_opt_flags : socket_opt_flags {
  68. non_blocking = SOCK_NONBLOCK,
  69. close_on_exec = SOCK_CLOEXEC,
  70. };
  71. using address = std::variant<sockaddr_in, sockaddr_in6, sockaddr_un>;
  72. template<typename T>
  73. struct stream_expect{
  74. const T v;
  75. stream_expect(T value)
  76. : v(value)
  77. {}
  78. };
  79. template<typename T>
  80. std::istream& operator>>(std::istream& in, const stream_expect<T>& expector)
  81. {
  82. T vin;
  83. in >> vin;
  84. if(vin != expector.v)
  85. throw std::runtime_error("Expector failed");
  86. return in;
  87. }
  88. address make_ipv4(const std::string_view addr, const uint16_t port)
  89. {
  90. std::stringstream din;
  91. din<<addr;
  92. std::array<uint8_t, 4> address{0};
  93. int ex;
  94. din>>ex
  95. >>stream_expect<char>('.');
  96. address[0]=ex;
  97. din>>ex
  98. >>stream_expect<char>('.');
  99. address[1]=ex;
  100. din>>ex
  101. >>stream_expect<char>('.');
  102. address[2]=ex;
  103. din>>ex;
  104. address[3]=ex;
  105. sockaddr_in ret;
  106. in_addr ret_addr;
  107. ret_addr.s_addr = *((uint32_t*)&address);
  108. ret.sin_family = AF_INET;
  109. ret.sin_addr = ret_addr;
  110. ret.sin_port = port;
  111. return ret;
  112. }
  113. // TODO: make an IPv6 parser
  114. //address make_ipv6(const std::string_view addr, const uint16_t port){}
  115. address make_unix(const std::string_view filename)
  116. {
  117. sockaddr_un ret;
  118. if(filename.size()>(sizeof(ret.sun_path)-1))
  119. throw std::runtime_error("Filename too long");
  120. ret.sun_family = AF_UNIX;
  121. *std::copy(filename.begin(), filename.end(), ret.sun_path) = '\0';
  122. return ret;
  123. }
  124. class shared_fd {
  125. int fd;
  126. std::atomic_int* guard;
  127. int last_error;
  128. shared_fd(int fd_v)
  129. : fd(fd_v)
  130. , guard(new std::atomic_int{1})
  131. , last_error(0)
  132. {}
  133. public:
  134. shared_fd()
  135. : fd(-1)
  136. , guard(nullptr)
  137. , last_error(0)
  138. {}
  139. shared_fd(const shared_fd& oth)
  140. : fd(oth.fd)
  141. , guard(oth.guard)
  142. , last_error(0)
  143. {
  144. if(guard)
  145. guard->fetch_add(1, std::memory_order_acq_rel);
  146. }
  147. shared_fd(shared_fd&& oth)
  148. : last_error(0)
  149. {
  150. fd=oth.fd;
  151. guard=oth.guard;
  152. oth.fd=-1;
  153. oth.guard=nullptr;
  154. }
  155. const int get() const {
  156. return fd;
  157. }
  158. void operator=(const shared_fd& oth)
  159. {
  160. this->~shared_fd();
  161. fd = oth.fd;
  162. guard = oth.guard;
  163. if(guard)
  164. guard->fetch_add(1, std::memory_order_acq_rel);
  165. }
  166. void operator=(shared_fd&& oth)
  167. {
  168. std::swap(fd,oth.fd);
  169. std::swap(guard,oth.guard);
  170. }
  171. static shared_fd open(const std::string& filename, const open_opt_flags& flags, const open_opt_mode& mode = 0)
  172. {
  173. shared_fd ret{::open(filename.c_str(), flags, mode)};
  174. return ret;
  175. }
  176. static shared_fd create(const std::string& filename, const open_opt_mode& mode)
  177. {
  178. shared_fd ret{::creat(filename.c_str(), mode)};
  179. return ret;
  180. }
  181. static shared_fd socket(const socket_domain& dom, const socket_protocol& proto, const net_socket_opt_flags& flags)
  182. {
  183. shared_fd ret;
  184. auto res = ::socket((int)dom, (int)proto, (int)flags);
  185. if(res >= 0)
  186. ret = shared_fd{res};
  187. return ret;
  188. }
  189. static shared_fd unix_socket(const socket_protocol& proto, const socket_opt_flags flags) {
  190. shared_fd ret;
  191. auto res = ::socket((int)AF_UNIX, (int)proto, (int)flags);
  192. if(res >= 0)
  193. ret = shared_fd{res};
  194. return ret;
  195. }
  196. static std::pair<shared_fd,shared_fd> unix_socket_pair(const socket_protocol& proto, const net_socket_opt_flags flags) {
  197. std::pair<gp::shared_fd, gp::shared_fd> ret;
  198. int fds[2];
  199. auto result = ::socketpair((int)AF_UNIX, (int)proto, (int)flags, fds);
  200. if(result != 0)
  201. return ret;
  202. ret.first = shared_fd(fds[0]);
  203. ret.second = shared_fd(fds[1]);
  204. return ret;
  205. }
  206. bool is_valid() const {
  207. return guard && (fd>=0);
  208. }
  209. bool has_failed() const {
  210. return last_error;
  211. }
  212. std::string_view read(const std::string_view buffer)
  213. {
  214. int sz = ::read(fd, (void*)(buffer.begin()), buffer.size());
  215. if(sz<0)
  216. last_error = errno;
  217. else
  218. last_error = 0;
  219. sz = sz<0?0:sz;
  220. return std::string_view(buffer.begin(), sz);
  221. }
  222. std::string_view write(const std::string_view buffer)
  223. {
  224. int sz = ::write(fd, (void*)(buffer.begin()), buffer.size());
  225. if(sz<0)
  226. last_error = errno;
  227. else
  228. last_error = 0;
  229. sz = sz<0?0:sz;
  230. return std::string_view(buffer.begin()+sz, buffer.size()-sz);
  231. }
  232. ~shared_fd()
  233. {
  234. if(guard)
  235. if(guard->fetch_sub(1, std::memory_order_acq_rel) == 1)
  236. {
  237. assert(guard->load() == 0);
  238. assert(fd >= 0);
  239. delete guard;
  240. guard = nullptr;
  241. if(fd >= 0)
  242. {
  243. ::close(fd);
  244. }
  245. }
  246. }
  247. };
  248. }