瀏覽代碼

Added a way to get the native fd

devel
Ludovic 'Archivist' Lagouardette 5 年之前
父節點
當前提交
a0bc24cdd4
共有 3 個文件被更改,包括 169 次插入14 次删除
  1. +3
    -3
      Makefile
  2. +91
    -10
      include/shared_fd.hpp
  3. +75
    -1
      tests/shared_fd.cpp

+ 3
- 3
Makefile 查看文件

@ -6,10 +6,10 @@ all: tests
tests: bin/tests
LLVM_PROFILE_FILE="./bin/tests.profraw" ./bin/tests
@llvm-profdata merge -sparse ./bin/tests.profraw -o ./bin/tests.profdata
@llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata $(wildcard ./tests/*.cpp) include/*.hpp
@llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata ./tests/*.cpp include/*.hpp | tail -n 1 | tr -s " " | sed -e 's/ /,/g' -- | awk -F "," '{print $$9}' | sed -e 's/^/Untested lines: /g'
@llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp
@llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp | tail -n 1 | tr -s " " | sed -e 's/ /,/g' -- | awk -F "," '{print $$9}' | sed -e 's/^/Untested lines: /g'
bin/tests: tests.cpp $(wildcard tests/*.cpp) ./tests/test_scaffold.h
bin/tests: tests.cpp $(wildcard tests/*.cpp) $(wildcard include/*.hpp) ./tests/test_scaffold.h
@mkdir -p $(@D)
$(CXX) $(CXXFLAGS) -Itests -Iinclude tests.cpp -o $@

+ 91
- 10
include/shared_fd.hpp 查看文件

@ -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);

+ 75
- 1
tests/shared_fd.cpp 查看文件

@ -42,6 +42,8 @@ struct manip_test : public test_scaffold {
int error = fd.is_valid()?0:1;
error += !(fd.get()>=0);
auto fd_cpy = fd;
error += fd_cpy.is_valid()?0:1;
@ -121,4 +123,76 @@ struct rw_err_test : public test_scaffold {
}
};
append_test dummy_l6987erd3(new rw_err_test{});
append_test dummy_l6987erd3(new rw_err_test{});
struct make_address_test : public test_scaffold {
make_address_test() {
name = __FILE__ ":6";
}
virtual int run() {
int error = 0;
gp::address ipv4 = gp::make_ipv4("127.0.0.1", 1234);
auto p = std::get<sockaddr_in>(ipv4);
error += (p.sin_family != AF_INET);
error += (p.sin_addr.s_addr != htonl(0x7F000001));
error += (p.sin_port != 1234);
try{
gp::make_ipv4("not an IP", 1234);
error += 1;
}catch(...){}
std::string filename = "/tmp/my_socket";
gp::address unix = gp::make_unix(filename);
auto q = std::get<sockaddr_un>(unix);
error += (q.sun_family != AF_UNIX);
error += strcmp(filename.c_str(), q.sun_path);
try{
std::string long_str(1024, 'p');
gp::make_unix(long_str);
error += 1;
}catch(...){}
return error;
}
};
append_test dummy_l6923ml3(new make_address_test{});
struct sockets_test : public test_scaffold {
sockets_test() {
name = __FILE__ ":7";
}
virtual int run() {
int error = 0;
auto v = gp::shared_fd::socket(gp::socket_domain::ip4, gp::socket_protocol::tcp_like, (gp::net_socket_opt_flags)0);
error += !(v.is_valid());
v = gp::shared_fd::socket(gp::socket_domain::ip4, gp::socket_protocol::tcp_like, (gp::net_socket_opt_flags)-1);
error += (v.is_valid());
auto pair_v = gp::shared_fd::unix_socket_pair(gp::socket_protocol::tcp_like, (gp::net_socket_opt_flags)0);
error += !(pair_v.first.is_valid());
error += !(pair_v.second.is_valid());
pair_v = gp::shared_fd::unix_socket_pair(gp::socket_protocol::tcp_like, (gp::net_socket_opt_flags)-1);
error += pair_v.first.is_valid();
error += pair_v.second.is_valid();
auto u_v = gp::shared_fd::unix_socket(gp::socket_protocol::tcp_like, (gp::socket_opt_flags)0);
error += !(u_v.is_valid());
u_v = gp::shared_fd::unix_socket(gp::socket_protocol::tcp_like, (gp::socket_opt_flags)-1);
error += u_v.is_valid();
return error;
}
};
append_test dummy_r3321443(new sockets_test{});

Loading…
取消
儲存