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.
 
 

208 regels
4.2 KiB

#pragma once
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include <atomic>
#include <cassert>
namespace gp{
using open_opt_flags = int;
enum class open_options : open_opt_flags {
append = O_APPEND,
create = O_CREAT,
async = O_ASYNC,
direct = O_DIRECT,
data_sync = O_DSYNC,
file_sync = O_SYNC,
exclusive = O_EXCL,
no_access_time = O_NOATIME,
no_follow = O_NOFOLLOW,
read = O_RDONLY,
write = O_WRONLY,
#ifdef O_TEMP
temporary = O_TEMP,
#endif
#ifdef O_TRUC
truncate = O_TRUC,
#endif
};
using open_opt_mode = int;
enum class open_modes : open_opt_mode {
user_read = S_IRUSR,
user_write = S_IWUSR,
user_exec = S_IXUSR,
group_read = S_IRGRP,
group_write = S_IWGRP,
group_exec = S_IXGRP,
other_read = S_IROTH,
other_write = S_IWOTH,
other_exec = S_IXOTH,
set_uid = S_ISUID,
set_gid = S_ISGID,
sticky_bit = S_ISVTX,
};
enum class net_socket_domain : int {
ip4 = AF_INET,
ip6 = AF_INET6
};
enum class net_socket_protocol : int {
tcp = SOCK_STREAM,
udp = SOCK_DGRAM
};
using socket_opt_flags = int;
enum class net_socket_opt_flags : socket_opt_flags {
non_blocking = SOCK_NONBLOCK,
close_on_exec = SOCK_CLOEXEC,
};
using socket_opt_flags = int;
enum class unix_socket_opt_flags : socket_opt_flags {
non_blocking = SOCK_NONBLOCK,
close_on_exec = SOCK_CLOEXEC,
};
class shared_fd {
int fd;
std::atomic_int* guard;
int last_error;
shared_fd(int fd_v)
: fd(fd_v)
, guard(new std::atomic_int{1})
, last_error(0)
{}
public:
shared_fd()
: fd(-1)
, guard(nullptr)
, last_error(0)
{}
shared_fd(const shared_fd& oth)
: fd(oth.fd)
, guard(oth.guard)
, last_error(0)
{
if(guard)
guard->fetch_add(1, std::memory_order_acq_rel);
}
shared_fd(shared_fd&& oth)
: last_error(0)
{
fd=oth.fd;
guard=oth.guard;
oth.fd=-1;
oth.guard=nullptr;
}
void operator=(const shared_fd& oth)
{
this->~shared_fd();
fd = oth.fd;
guard = oth.guard;
if(guard)
guard->fetch_add(1, std::memory_order_acq_rel);
}
void operator=(shared_fd&& oth)
{
std::swap(fd,oth.fd);
std::swap(guard,oth.guard);
}
static shared_fd open(const std::string& filename, const open_opt_flags& flags, const open_opt_mode& mode = 0)
{
shared_fd ret{::open(filename.c_str(), flags, mode)};
return ret;
}
static shared_fd create(const std::string& filename, const open_opt_mode& mode)
{
shared_fd ret{::creat(filename.c_str(), mode)};
return ret;
}
static shared_fd net_socket(const net_socket_domain& dom, const net_socket_protocol& proto, net_socket_opt_flags& flags)
{
shared_fd ret{::socket((int)dom, (int)proto, (int)flags)};
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)};
return ret;
}
static std::pair<shared_fd,shared_fd> unix_socket_pair(const net_socket_protocol& proto, const 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);
if(result != 0)
return ret;
ret.first = shared_fd(fds[0]);
ret.second = shared_fd(fds[1]);
return ret;
}
bool is_valid() const {
return guard && (fd>=0);
}
bool has_failed() const {
return last_error;
}
std::string_view read(const std::string_view buffer)
{
int sz = ::read(fd, (void*)(buffer.begin()), buffer.size());
if(sz<0)
last_error = errno;
else
last_error = 0;
sz = sz<0?0:sz;
return std::string_view(buffer.begin(), sz);
}
std::string_view write(const std::string_view buffer)
{
int sz = ::write(fd, (void*)(buffer.begin()), buffer.size());
if(sz<0)
last_error = errno;
else
last_error = 0;
sz = sz<0?0:sz;
return std::string_view(buffer.begin()+sz, buffer.size()-sz);
}
~shared_fd()
{
if(guard)
if(guard->fetch_sub(1, std::memory_order_acq_rel) == 1)
{
assert(guard->load() == 0);
assert(fd >= 0);
delete guard;
guard = nullptr;
if(fd >= 0)
{
::close(fd);
}
}
}
};
}