1 #include "Connection.hpp"
7 #if !(HAVE_SOCK_NONBLOCK && HAVE_SOCK_CLOEXEC)
9 # define SOCK_NONBLOCK O_NONBLOCK
10 # define SOCK_CLOEXEC O_CLOEXEC
13 static inline int socket_ex(int af
, int so
, int pf
, int fl
) {
14 #if HAVE_SOCK_NONBLOCK && HAVE_SOCK_CLOEXEC
15 return socket(af
, so
| fl
, pf
);
17 auto sock
= socket(af
, so
, pf
);
19 if (0 > fcntl(sock
, F_SETFL
, fl
| fcntl(sock
, F_GETFL
))) {
28 Connection::Connection(socket_or_port_t socket_or_port
) {
29 if (holds_alternative
<string
>(socket_or_port
)) {
30 const auto path
= get
<string
>(socket_or_port
);
31 const auto safe
= path
.c_str();
32 const auto zlen
= path
.length() + 1;
33 const auto ulen
= sizeof(sockaddr_un
) - sizeof(sa_family_t
);
36 throw invalid_argument(error({"socket(): path too long '", path
, "'"}));
39 if (0 > (sock
= socket_ex(AF_UNIX
, SOCK_STREAM
, 0, SOCK_NONBLOCK
|SOCK_CLOEXEC
))) {
40 throw runtime_error(error({"socket(): ", strerror(errno
)}));
43 auto sa
= reinterpret_cast<sockaddr_un
*>(&addr
);
44 sa
->sun_family
= AF_UNIX
;
45 copy(safe
, safe
+ zlen
, sa
->sun_path
);
50 if (0 > (sock
= socket_ex(AF_INET6
, SOCK_STREAM
, 0, SOCK_NONBLOCK
|SOCK_CLOEXEC
))) {
51 throw runtime_error(error({"socket(): ", strerror(errno
)}));
54 const auto port
= get
<int>(socket_or_port
);
55 auto sa
= reinterpret_cast<struct sockaddr_in6
*>(&addr
);
56 sa
->sin6_family
= AF_INET6
;
57 sa
->sin6_port
= htons(static_cast<unsigned short>(port
));
58 sa
->sin6_addr
= IN6ADDR_LOOPBACK_INIT
;
64 Connection::~Connection() {
68 void swap(Connection
&a
, Connection
&b
) {
72 void Connection::swap(Connection
&conn
) {
73 Connection
copy(conn
);
77 conn
.last_err
= last_err
;
78 sock
= exchange(copy
.sock
, -1);
81 last_err
= copy
.last_err
;
84 Connection::Connection(const Connection
&conn
) {
86 sock
= dup(conn
.sock
);
90 last_err
= conn
.last_err
;
93 Connection
&Connection::operator=(const Connection
&conn
) {
94 Connection
copy(conn
);
99 Connection::Connection(Connection
&&conn
) noexcept
{
104 Connection
&Connection::operator=(Connection
&&conn
) noexcept
{
105 Connection
copy(move(conn
));
110 void Connection::close() {
118 int Connection::getError() {
120 socklen_t len
= sizeof(int);
123 if (0 > getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, &err
, &len
)) {
131 int Connection::getLastError() {
132 if (last_err
== -1) {
138 bool Connection::isWritable() {
139 pollfd fd
{sock
, POLLOUT
, 0};
140 if (1 > poll(&fd
, 1, 0)) {
143 if (fd
.revents
& (POLLNVAL
|POLLERR
|POLLHUP
)) {
146 return fd
.revents
& POLLOUT
;
149 bool Connection::isOpen() {
152 return getError() == 0;
155 return getError() == 0;
162 bool Connection::open() {
168 if (0 == ::connect(sock
, reinterpret_cast<sockaddr
*>(&addr
), size
)) {
189 string
Connection::error(const initializer_list
<string
> &args
) {
192 for (const auto &arg
: args
) {