|
|
@ -5,8 +5,13 @@ |
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <string>
|
|
|
|
#include <sstream>
|
|
|
|
#include <atomic>
|
|
|
|
#include <array>
|
|
|
|
#include <variant>
|
|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
namespace gp{ |
|
|
@ -49,14 +54,15 @@ namespace gp{ |
|
|
|
sticky_bit = S_ISVTX, |
|
|
|
}; |
|
|
|
|
|
|
|
enum class net_socket_domain : int { |
|
|
|
enum class socket_domain : int { |
|
|
|
ip4 = AF_INET, |
|
|
|
ip6 = AF_INET6 |
|
|
|
ip6 = AF_INET6, |
|
|
|
unix = AF_UNIX |
|
|
|
}; |
|
|
|
|
|
|
|
enum class net_socket_protocol : int { |
|
|
|
tcp = SOCK_STREAM, |
|
|
|
udp = SOCK_DGRAM |
|
|
|
enum class socket_protocol : int { |
|
|
|
tcp_like = SOCK_STREAM, |
|
|
|
udp_like = SOCK_DGRAM |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -74,6 +80,67 @@ namespace gp{ |
|
|
|
close_on_exec = SOCK_CLOEXEC, |
|
|
|
}; |
|
|
|
|
|
|
|
using address = std::variant<sockaddr_in, sockaddr_in6, sockaddr_un>; |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
struct stream_expect{ |
|
|
|
const T v; |
|
|
|
stream_expect(T value) |
|
|
|
: v(value) |
|
|
|
{} |
|
|
|
}; |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
std::istream& operator>>(std::istream& in, const stream_expect<T>& expector) |
|
|
|
{ |
|
|
|
T vin; |
|
|
|
in >> vin; |
|
|
|
if(vin != expector.v) |
|
|
|
throw std::runtime_error("Expector failed"); |
|
|
|
return in; |
|
|
|
} |
|
|
|
|
|
|
|
address make_ipv4(const std::string_view addr, const uint16_t port) |
|
|
|
{ |
|
|
|
std::stringstream din; |
|
|
|
din<<addr; |
|
|
|
std::array<uint8_t, 4> address{0}; |
|
|
|
int ex; |
|
|
|
din>>ex |
|
|
|
>>stream_expect<char>('.'); |
|
|
|
address[0]=ex; |
|
|
|
din>>ex |
|
|
|
>>stream_expect<char>('.'); |
|
|
|
address[1]=ex; |
|
|
|
din>>ex |
|
|
|
>>stream_expect<char>('.'); |
|
|
|
address[2]=ex; |
|
|
|
din>>ex; |
|
|
|
address[3]=ex; |
|
|
|
|
|
|
|
sockaddr_in ret; |
|
|
|
in_addr ret_addr; |
|
|
|
ret_addr.s_addr = *((uint32_t*)&address); |
|
|
|
ret.sin_family = AF_INET; |
|
|
|
ret.sin_addr = ret_addr; |
|
|
|
ret.sin_port = port; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: make an IPv6 parser
|
|
|
|
//address make_ipv6(const std::string_view addr, const uint16_t port){}
|
|
|
|
|
|
|
|
address make_unix(const std::string_view filename) |
|
|
|
{ |
|
|
|
sockaddr_un ret; |
|
|
|
if(filename.size()>(sizeof(ret.sun_path)-1)) |
|
|
|
throw std::runtime_error("Filename too long"); |
|
|
|
|
|
|
|
ret.sun_family = AF_UNIX; |
|
|
|
*std::copy(filename.begin(), filename.end(), ret.sun_path) = '\0'; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
class shared_fd { |
|
|
|
int fd; |
|
|
|
std::atomic_int* guard; |
|
|
@ -109,6 +176,10 @@ namespace gp{ |
|
|
|
oth.guard=nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
const int get() const { |
|
|
|
return fd; |
|
|
|
} |
|
|
|
|
|
|
|
void operator=(const shared_fd& oth) |
|
|
|
{ |
|
|
|
this->~shared_fd(); |
|
|
@ -136,18 +207,28 @@ namespace gp{ |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static shared_fd net_socket(const net_socket_domain& dom, const net_socket_protocol& proto, net_socket_opt_flags& flags) |
|
|
|
static shared_fd socket(const socket_domain& dom, const socket_protocol& proto, const net_socket_opt_flags& flags) |
|
|
|
{ |
|
|
|
shared_fd ret{::socket((int)dom, (int)proto, (int)flags)}; |
|
|
|
shared_fd ret; |
|
|
|
|
|
|
|
auto res = ::socket((int)dom, (int)proto, (int)flags); |
|
|
|
if(res >= 0) |
|
|
|
ret = shared_fd{res}; |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static shared_fd unix_socket(const net_socket_protocol& proto, const socket_opt_flags flags) { |
|
|
|
shared_fd ret{::socket((int)AF_UNIX, (int)proto, (int)flags)}; |
|
|
|
static shared_fd unix_socket(const socket_protocol& proto, const socket_opt_flags flags) { |
|
|
|
shared_fd ret; |
|
|
|
|
|
|
|
auto res = ::socket((int)AF_UNIX, (int)proto, (int)flags); |
|
|
|
if(res >= 0) |
|
|
|
ret = shared_fd{res}; |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static std::pair<shared_fd,shared_fd> unix_socket_pair(const net_socket_protocol& proto, const socket_opt_flags flags) { |
|
|
|
static std::pair<shared_fd,shared_fd> unix_socket_pair(const socket_protocol& proto, const net_socket_opt_flags flags) { |
|
|
|
std::pair<gp::shared_fd, gp::shared_fd> ret; |
|
|
|
int fds[2]; |
|
|
|
auto result = ::socketpair((int)AF_UNIX, (int)proto, (int)flags, fds); |
|
|
|