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.

382 lines
7.3 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. // TODO: Scavenge for useful parts and discard
  17. namespace gp{
  18. using open_opt_flags = int;
  19. enum class open_options : open_opt_flags {
  20. append = O_APPEND,
  21. create = O_CREAT,
  22. async = O_ASYNC,
  23. direct = O_DIRECT,
  24. data_sync = O_DSYNC,
  25. file_sync = O_SYNC,
  26. exclusive = O_EXCL,
  27. no_access_time = O_NOATIME,
  28. no_follow = O_NOFOLLOW,
  29. read = O_RDONLY,
  30. write = O_WRONLY,
  31. #ifdef O_TEMP
  32. temporary = O_TEMP,
  33. #endif
  34. #ifdef O_TRUC
  35. truncate = O_TRUC,
  36. #endif
  37. };
  38. using open_opt_mode = int;
  39. enum class open_modes : open_opt_mode {
  40. user_read = S_IRUSR,
  41. user_write = S_IWUSR,
  42. user_exec = S_IXUSR,
  43. group_read = S_IRGRP,
  44. group_write = S_IWGRP,
  45. group_exec = S_IXGRP,
  46. other_read = S_IROTH,
  47. other_write = S_IWOTH,
  48. other_exec = S_IXOTH,
  49. set_uid = S_ISUID,
  50. set_gid = S_ISGID,
  51. sticky_bit = S_ISVTX,
  52. };
  53. enum class socket_domain : int {
  54. ip4 = AF_INET,
  55. ip6 = AF_INET6,
  56. unix = AF_UNIX
  57. };
  58. enum class socket_protocol : int {
  59. tcp_like = SOCK_STREAM,
  60. udp_like = SOCK_DGRAM
  61. };
  62. using socket_opt_flags = int;
  63. enum class net_socket_opt_flags : socket_opt_flags {
  64. non_blocking = SOCK_NONBLOCK,
  65. close_on_exec = SOCK_CLOEXEC,
  66. };
  67. using socket_opt_flags = int;
  68. enum class unix_socket_opt_flags : socket_opt_flags {
  69. non_blocking = SOCK_NONBLOCK,
  70. close_on_exec = SOCK_CLOEXEC,
  71. };
  72. using address = std::variant<sockaddr_in, sockaddr_in6, sockaddr_un>;
  73. template<typename T>
  74. struct stream_expect{
  75. const T v;
  76. stream_expect(T value)
  77. : v(value)
  78. {}
  79. };
  80. template<typename T>
  81. std::istream& operator>>(std::istream& in, const stream_expect<T>& expector)
  82. {
  83. T vin;
  84. in >> vin;
  85. if(vin != expector.v)
  86. throw std::runtime_error("Expector failed");
  87. return in;
  88. }
  89. address make_ipv4(const std::string_view addr, const uint16_t port)
  90. {
  91. std::stringstream din;
  92. din<<addr;
  93. std::array<uint8_t, 4> address{0};
  94. int ex;
  95. din>>ex
  96. >>stream_expect<char>('.');
  97. address[0]=ex;
  98. din>>ex
  99. >>stream_expect<char>('.');
  100. address[1]=ex;
  101. din>>ex
  102. >>stream_expect<char>('.');
  103. address[2]=ex;
  104. din>>ex;
  105. address[3]=ex;
  106. sockaddr_in ret;
  107. in_addr ret_addr;
  108. ret_addr.s_addr = *((uint32_t*)&address);
  109. ret.sin_family = AF_INET;
  110. ret.sin_addr = ret_addr;
  111. ret.sin_port = htons(port);
  112. return ret;
  113. }
  114. // TODO: make an IPv6 parser
  115. //address make_ipv6(const std::string_view addr, const uint16_t port){}
  116. address make_unix(const std::string_view filename)
  117. {
  118. sockaddr_un ret;
  119. if(filename.size()>(sizeof(ret.sun_path)-1))
  120. throw std::runtime_error("Filename too long");
  121. ret.sun_family = AF_UNIX;
  122. *std::copy(filename.begin(), filename.end(), ret.sun_path) = '\0';
  123. return ret;
  124. }
  125. class shared_fd {
  126. int fd;
  127. std::atomic_int* guard;
  128. int last_error;
  129. shared_fd(int fd_v)
  130. : fd(fd_v)
  131. , guard(new std::atomic_int{1})
  132. , last_error(0)
  133. {}
  134. public:
  135. shared_fd()
  136. : fd(-1)
  137. , guard(nullptr)
  138. , last_error(0)
  139. {}
  140. shared_fd(const shared_fd& oth)
  141. : fd(oth.fd)
  142. , guard(oth.guard)
  143. , last_error(0)
  144. {
  145. if(guard)
  146. guard->fetch_add(1, std::memory_order_acq_rel);
  147. }
  148. shared_fd(shared_fd&& oth)
  149. : last_error(0)
  150. {
  151. fd=oth.fd;
  152. guard=oth.guard;
  153. oth.fd=-1;
  154. oth.guard=nullptr;
  155. }
  156. const int get() const {
  157. return fd;
  158. }
  159. void operator=(const shared_fd& oth)
  160. {
  161. this->~shared_fd();
  162. fd = oth.fd;
  163. guard = oth.guard;
  164. if(guard)
  165. guard->fetch_add(1, std::memory_order_acq_rel);
  166. }
  167. void operator=(shared_fd&& oth)
  168. {
  169. std::swap(fd,oth.fd);
  170. std::swap(guard,oth.guard);
  171. }
  172. static shared_fd open(const std::string& filename, const open_opt_flags& flags, const open_opt_mode& mode = 0)
  173. {
  174. shared_fd ret{::open(filename.c_str(), flags, mode)};
  175. return ret;
  176. }
  177. static shared_fd create(const std::string& filename, const open_opt_mode& mode)
  178. {
  179. shared_fd ret{::creat(filename.c_str(), mode)};
  180. return ret;
  181. }
  182. static shared_fd tcp_socket()
  183. {
  184. shared_fd ret;
  185. auto res = ::socket(AF_INET, SOCK_STREAM, 0);
  186. if(res >= 0)
  187. {
  188. ret = shared_fd{res};
  189. fcntl(res, F_SETFL, O_NONBLOCK);
  190. }
  191. else
  192. ret.last_error = errno;
  193. return ret;
  194. }
  195. static shared_fd socket(const socket_domain& dom, const socket_protocol& proto)//, const net_socket_opt_flags& flags)
  196. {
  197. shared_fd ret;
  198. auto res = ::socket((int)dom, (int)proto, (int)0);
  199. if(res >= 0)
  200. {
  201. ret = shared_fd{res};
  202. }
  203. else
  204. ret.last_error = errno;
  205. return ret;
  206. }
  207. static shared_fd unix_socket(const socket_protocol& proto, const socket_opt_flags flags) {
  208. shared_fd ret;
  209. auto res = ::socket((int)AF_UNIX, (int)proto, (int)flags);
  210. if(res >= 0)
  211. ret = shared_fd{res};
  212. return ret;
  213. }
  214. static std::pair<shared_fd,shared_fd> unix_socket_pair(const socket_protocol& proto, const net_socket_opt_flags flags) {
  215. std::pair<gp::shared_fd, gp::shared_fd> ret;
  216. int fds[2];
  217. auto result = ::socketpair((int)AF_UNIX, (int)proto, (int)flags, fds);
  218. if(result != 0)
  219. return ret;
  220. ret.first = shared_fd(fds[0]);
  221. ret.second = shared_fd(fds[1]);
  222. return ret;
  223. }
  224. bool is_valid() const {
  225. return guard && (fd>=0);
  226. }
  227. bool has_failed() const {
  228. return last_error;
  229. }
  230. bool was_connection_refused() const {
  231. return last_error==ECONNREFUSED;
  232. }
  233. bool in_progress() const {
  234. return last_error==EINPROGRESS;
  235. }
  236. bool must_retry() const {
  237. return last_error==EAGAIN;
  238. }
  239. int error() const {
  240. return last_error;
  241. }
  242. void bind(const address& addr)
  243. {
  244. int ret;
  245. std::visit([&](const auto& v){
  246. ret = ::bind(fd, (struct sockaddr*)&v, sizeof(v));
  247. }, addr);
  248. if(ret==0)
  249. {
  250. last_error = 0;
  251. return;
  252. }
  253. else
  254. last_error = errno;
  255. }
  256. void connect(const address& addr)
  257. {
  258. int ret;
  259. std::visit([&](const auto& v){
  260. ret = ::connect(fd, (struct sockaddr*)&v, sizeof(v));
  261. }, addr);
  262. if(ret!=0)
  263. {
  264. last_error = errno;
  265. return;
  266. }
  267. last_error = 0;
  268. }
  269. void listen(const int& backlog = 16)
  270. {
  271. int ret = 0;
  272. std::visit([&](){
  273. ret = ::listen(fd, backlog);
  274. });
  275. if(ret!=0)
  276. {
  277. last_error = errno;
  278. return;
  279. }
  280. last_error = 0;
  281. }
  282. shared_fd accept()
  283. {
  284. int ret = 0;
  285. std::array<uint8_t, 256> buffer;
  286. socklen_t len;
  287. ret = ::accept(fd,(sockaddr*)buffer.begin(), &len);
  288. if(ret!=0)
  289. {
  290. last_error = errno;
  291. return shared_fd{};
  292. }
  293. last_error = 0;
  294. return shared_fd{ret};
  295. }
  296. std::string_view read(const std::string_view buffer)
  297. {
  298. int sz = ::read(fd, (void*)(buffer.begin()), buffer.size());
  299. if(sz<0)
  300. last_error = errno;
  301. else
  302. last_error = 0;
  303. sz = sz<0?0:sz;
  304. return std::string_view(buffer.begin(), sz);
  305. }
  306. std::string_view write(const std::string_view buffer)
  307. {
  308. int sz = ::write(fd, (void*)(buffer.begin()), buffer.size());
  309. if(sz<0)
  310. last_error = errno;
  311. else
  312. last_error = 0;
  313. sz = sz<0?0:sz;
  314. return std::string_view(buffer.begin()+sz, buffer.size()-sz);
  315. }
  316. ~shared_fd()
  317. {
  318. if(guard)
  319. if(guard->fetch_sub(1, std::memory_order_acq_rel) == 1)
  320. {
  321. assert(guard->load() == 0);
  322. assert(fd >= 0);
  323. delete guard;
  324. guard = nullptr;
  325. if(fd >= 0)
  326. {
  327. ::close(fd);
  328. }
  329. }
  330. }
  331. };
  332. }