General Purpose library for Freestanding C++ and POSIX systems
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

207 řádky
4.2 KiB

před 5 roky
před 5 roky
  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 <string>
  9. #include <atomic>
  10. #include <cassert>
  11. namespace gp{
  12. using open_opt_flags = int;
  13. enum class open_options : open_opt_flags {
  14. append = O_APPEND,
  15. create = O_CREAT,
  16. async = O_ASYNC,
  17. direct = O_DIRECT,
  18. data_sync = O_DSYNC,
  19. file_sync = O_SYNC,
  20. exclusive = O_EXCL,
  21. no_access_time = O_NOATIME,
  22. no_follow = O_NOFOLLOW,
  23. read = O_RDONLY,
  24. write = O_WRONLY,
  25. #ifdef O_TEMP
  26. temporary = O_TEMP,
  27. #endif
  28. #ifdef O_TRUC
  29. truncate = O_TRUC,
  30. #endif
  31. };
  32. using open_opt_mode = int;
  33. enum class open_modes : open_opt_mode {
  34. user_read = S_IRUSR,
  35. user_write = S_IWUSR,
  36. user_exec = S_IXUSR,
  37. group_read = S_IRGRP,
  38. group_write = S_IWGRP,
  39. group_exec = S_IXGRP,
  40. other_read = S_IROTH,
  41. other_write = S_IWOTH,
  42. other_exec = S_IXOTH,
  43. set_uid = S_ISUID,
  44. set_gid = S_ISGID,
  45. sticky_bit = S_ISVTX,
  46. };
  47. enum class net_socket_domain : int {
  48. ip4 = AF_INET,
  49. ip6 = AF_INET6
  50. };
  51. enum class net_socket_protocol : int {
  52. tcp = SOCK_STREAM,
  53. udp = SOCK_DGRAM
  54. };
  55. using socket_opt_flags = int;
  56. enum class net_socket_opt_flags : socket_opt_flags {
  57. non_blocking = SOCK_NONBLOCK,
  58. close_on_exec = SOCK_CLOEXEC,
  59. };
  60. using socket_opt_flags = int;
  61. enum class unix_socket_opt_flags : socket_opt_flags {
  62. non_blocking = SOCK_NONBLOCK,
  63. close_on_exec = SOCK_CLOEXEC,
  64. };
  65. class shared_fd {
  66. int fd;
  67. std::atomic_int* guard;
  68. int last_error;
  69. shared_fd(int fd_v)
  70. : fd(fd_v)
  71. , guard(new std::atomic_int{1})
  72. , last_error(0)
  73. {}
  74. public:
  75. shared_fd()
  76. : fd(-1)
  77. , guard(nullptr)
  78. , last_error(0)
  79. {}
  80. shared_fd(const shared_fd& oth)
  81. : fd(oth.fd)
  82. , guard(oth.guard)
  83. , last_error(0)
  84. {
  85. if(guard)
  86. guard->fetch_add(1, std::memory_order_acq_rel);
  87. }
  88. shared_fd(shared_fd&& oth)
  89. : last_error(0)
  90. {
  91. fd=oth.fd;
  92. guard=oth.guard;
  93. oth.fd=-1;
  94. oth.guard=nullptr;
  95. }
  96. void operator=(const shared_fd& oth)
  97. {
  98. this->~shared_fd();
  99. fd = oth.fd;
  100. guard = oth.guard;
  101. if(guard)
  102. guard->fetch_add(1, std::memory_order_acq_rel);
  103. }
  104. void operator=(shared_fd&& oth)
  105. {
  106. std::swap(fd,oth.fd);
  107. std::swap(guard,oth.guard);
  108. }
  109. static shared_fd open(const std::string& filename, const open_opt_flags& flags, const open_opt_mode& mode = 0)
  110. {
  111. shared_fd ret{::open(filename.c_str(), flags, mode)};
  112. return ret;
  113. }
  114. static shared_fd create(const std::string& filename, const open_opt_mode& mode)
  115. {
  116. shared_fd ret{::creat(filename.c_str(), mode)};
  117. return ret;
  118. }
  119. static shared_fd net_socket(const net_socket_domain& dom, const net_socket_protocol& proto, net_socket_opt_flags& flags)
  120. {
  121. shared_fd ret{::socket((int)dom, (int)proto, (int)flags)};
  122. return ret;
  123. }
  124. static shared_fd unix_socket(const net_socket_protocol& proto, const socket_opt_flags flags) {
  125. shared_fd ret{::socket((int)AF_UNIX, (int)proto, (int)flags)};
  126. return ret;
  127. }
  128. static std::pair<shared_fd,shared_fd> unix_socketpair(const net_socket_protocol& proto, const socket_opt_flags flags) {
  129. std::pair<gp::shared_fd, gp::shared_fd> ret;
  130. int fds[2];
  131. auto result = ::socketpair((int)AF_UNIX, (int)proto, (int)flags, fds);
  132. if(result != 0)
  133. return ret;
  134. ret.first = shared_fd(fds[0]);
  135. ret.second = shared_fd(fds[1]);
  136. return ret;
  137. }
  138. bool is_valid() const {
  139. return guard && (fd>=0);
  140. }
  141. bool has_failed() const {
  142. return last_error;
  143. }
  144. std::string_view read(const std::string_view buffer)
  145. {
  146. int sz = ::read(fd, (void*)(buffer.begin()), buffer.size());
  147. if(sz<0)
  148. last_error = errno;
  149. else
  150. last_error = 0;
  151. sz = sz<0?0:sz;
  152. return std::string_view(buffer.begin(), sz);
  153. }
  154. std::string_view write(const std::string_view buffer)
  155. {
  156. int sz = ::write(fd, (void*)(buffer.begin()), buffer.size());
  157. if(sz<0)
  158. last_error = errno;
  159. else
  160. last_error = 0;
  161. sz = sz<0?0:sz;
  162. return std::string_view(buffer.begin()+sz, buffer.size()-sz);
  163. }
  164. ~shared_fd()
  165. {
  166. if(guard)
  167. if(guard->fetch_sub(1, std::memory_order_acq_rel) == 1)
  168. {
  169. assert(guard->load() == 0);
  170. assert(fd >= 0);
  171. delete guard;
  172. guard = nullptr;
  173. if(fd >= 0)
  174. {
  175. ::close(fd);
  176. }
  177. }
  178. }
  179. };
  180. }