General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

380 lines
7.2 KiB

4 years ago
4 years ago
  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 = htons(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 tcp_socket()
  182. {
  183. shared_fd ret;
  184. auto res = ::socket(AF_INET, SOCK_STREAM, 0);
  185. if(res >= 0)
  186. {
  187. ret = shared_fd{res};
  188. fcntl(res, F_SETFL, O_NONBLOCK);
  189. }
  190. else
  191. ret.last_error = errno;
  192. return ret;
  193. }
  194. static shared_fd socket(const socket_domain& dom, const socket_protocol& proto)//, const net_socket_opt_flags& flags)
  195. {
  196. shared_fd ret;
  197. auto res = ::socket((int)dom, (int)proto, (int)0);
  198. if(res >= 0)
  199. {
  200. ret = shared_fd{res};
  201. }
  202. else
  203. ret.last_error = errno;
  204. return ret;
  205. }
  206. static shared_fd unix_socket(const socket_protocol& proto, const socket_opt_flags flags) {
  207. shared_fd ret;
  208. auto res = ::socket((int)AF_UNIX, (int)proto, (int)flags);
  209. if(res >= 0)
  210. ret = shared_fd{res};
  211. return ret;
  212. }
  213. static std::pair<shared_fd,shared_fd> unix_socket_pair(const socket_protocol& proto, const net_socket_opt_flags flags) {
  214. std::pair<gp::shared_fd, gp::shared_fd> ret;
  215. int fds[2];
  216. auto result = ::socketpair((int)AF_UNIX, (int)proto, (int)flags, fds);
  217. if(result != 0)
  218. return ret;
  219. ret.first = shared_fd(fds[0]);
  220. ret.second = shared_fd(fds[1]);
  221. return ret;
  222. }
  223. bool is_valid() const {
  224. return guard && (fd>=0);
  225. }
  226. bool has_failed() const {
  227. return last_error;
  228. }
  229. bool was_connection_refused() const {
  230. return last_error==ECONNREFUSED;
  231. }
  232. bool in_progress() const {
  233. return last_error==EINPROGRESS;
  234. }
  235. bool must_retry() const {
  236. return last_error==EAGAIN;
  237. }
  238. int error() const {
  239. return last_error;
  240. }
  241. void bind(const address& addr)
  242. {
  243. int ret;
  244. std::visit([&](const auto& v){
  245. ret = ::bind(fd, (struct sockaddr*)&v, sizeof(v));
  246. }, addr);
  247. if(ret==0)
  248. {
  249. last_error = 0;
  250. return;
  251. }
  252. else
  253. last_error = errno;
  254. }
  255. void connect(const address& addr)
  256. {
  257. int ret;
  258. std::visit([&](const auto& v){
  259. ret = ::connect(fd, (struct sockaddr*)&v, sizeof(v));
  260. }, addr);
  261. if(ret!=0)
  262. {
  263. last_error = errno;
  264. return;
  265. }
  266. last_error = 0;
  267. }
  268. void listen(const int& backlog = 16)
  269. {
  270. int ret = 0;
  271. std::visit([&](){
  272. ret = ::listen(fd, backlog);
  273. });
  274. if(ret!=0)
  275. {
  276. last_error = errno;
  277. return;
  278. }
  279. last_error = 0;
  280. }
  281. shared_fd accept()
  282. {
  283. int ret = 0;
  284. std::array<uint8_t, 256> buffer;
  285. socklen_t len;
  286. ret = ::accept(fd,(sockaddr*)buffer.begin(), &len);
  287. if(ret!=0)
  288. {
  289. last_error = errno;
  290. return shared_fd{};
  291. }
  292. last_error = 0;
  293. return shared_fd{ret};
  294. }
  295. std::string_view read(const std::string_view buffer)
  296. {
  297. int sz = ::read(fd, (void*)(buffer.begin()), buffer.size());
  298. if(sz<0)
  299. last_error = errno;
  300. else
  301. last_error = 0;
  302. sz = sz<0?0:sz;
  303. return std::string_view(buffer.begin(), sz);
  304. }
  305. std::string_view write(const std::string_view buffer)
  306. {
  307. int sz = ::write(fd, (void*)(buffer.begin()), buffer.size());
  308. if(sz<0)
  309. last_error = errno;
  310. else
  311. last_error = 0;
  312. sz = sz<0?0:sz;
  313. return std::string_view(buffer.begin()+sz, buffer.size()-sz);
  314. }
  315. ~shared_fd()
  316. {
  317. if(guard)
  318. if(guard->fetch_sub(1, std::memory_order_acq_rel) == 1)
  319. {
  320. assert(guard->load() == 0);
  321. assert(fd >= 0);
  322. delete guard;
  323. guard = nullptr;
  324. if(fd >= 0)
  325. {
  326. ::close(fd);
  327. }
  328. }
  329. }
  330. };
  331. }