1 #include "Connection.hpp"
2 #include "p9y/poll.hpp"
9 #if !(HAVE_SOCK_NONBLOCK && HAVE_SOCK_CLOEXEC)
11 # define SOCK_NONBLOCK O_NONBLOCK
12 # define SOCK_CLOEXEC O_CLOEXEC
15 static inline int socket_ex(int af
, int so
, int pf
, int fl
) {
16 #if HAVE_SOCK_NONBLOCK && HAVE_SOCK_CLOEXEC
17 return socket(af
, so
| fl
, pf
);
19 auto sock
= socket(af
, so
, pf
);
21 if (0 > fcntl(sock
, F_SETFL
, fl
| fcntl(sock
, F_GETFL
))) {
30 Connection::Connection(socket_or_port_t socket_or_port
) {
31 if (holds_alternative
<string
>(socket_or_port
)) {
32 const auto path
= get
<string
>(socket_or_port
);
33 const auto safe
= path
.c_str();
34 const auto zlen
= path
.length() + 1;
35 const auto ulen
= sizeof(sockaddr_un
) - sizeof(sa_family_t
);
38 throw invalid_argument(error({"socket(): path too long '", path
, "'"}));
41 if (0 > (sock
= socket_ex(AF_UNIX
, SOCK_STREAM
, 0, SOCK_NONBLOCK
|SOCK_CLOEXEC
))) {
42 throw runtime_error(error({"socket(): ", strerror(errno
)}));
45 auto sa
= reinterpret_cast<sockaddr_un
*>(&addr
);
46 sa
->sun_family
= AF_UNIX
;
47 copy(safe
, safe
+ zlen
, sa
->sun_path
);
52 if (0 > (sock
= socket_ex(AF_INET6
, SOCK_STREAM
, 0, SOCK_NONBLOCK
|SOCK_CLOEXEC
))) {
53 throw runtime_error(error({"socket(): ", strerror(errno
)}));
56 const auto port
= get
<int>(socket_or_port
);
57 auto sa
= reinterpret_cast<struct sockaddr_in6
*>(&addr
);
58 sa
->sin6_family
= AF_INET6
;
59 sa
->sin6_port
= htons(static_cast<unsigned short>(port
));
60 sa
->sin6_addr
= IN6ADDR_LOOPBACK_INIT
;
66 Connection::~Connection() {
70 void swap(Connection
&a
, Connection
&b
) {
74 void Connection::swap(Connection
&conn
) {
75 Connection
copy(conn
);
79 conn
.last_err
= last_err
;
80 sock
= exchange(copy
.sock
, -1);
83 last_err
= copy
.last_err
;
86 Connection::Connection(const Connection
&conn
) {
88 sock
= dup(conn
.sock
);
92 last_err
= conn
.last_err
;
95 Connection
&Connection::operator=(const Connection
&conn
) {
96 Connection
copy(conn
);
101 Connection::Connection(Connection
&&conn
) noexcept
{
106 Connection
&Connection::operator=(Connection
&&conn
) noexcept
{
107 Connection
copy(move(conn
));
112 void Connection::close() {
120 int Connection::getError() {
122 socklen_t len
= sizeof(int);
125 if (0 > getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, &err
, &len
)) {
133 int Connection::getLastError() {
134 if (last_err
== -1) {
140 bool Connection::isWritable() {
141 pollfd fd
{sock
, POLLOUT
, 0};
142 if (1 > poll(&fd
, 1, 0)) {
145 if (fd
.revents
& (POLLNVAL
|POLLERR
|POLLHUP
)) {
148 return fd
.revents
& POLLOUT
;
151 bool Connection::isOpen() {
154 return getError() == 0;
157 return getError() == 0;
164 bool Connection::open() {
170 if (0 == ::connect(sock
, reinterpret_cast<sockaddr
*>(&addr
), size
)) {
191 string
Connection::error(const initializer_list
<string
> &args
) {
194 for (const auto &arg
: args
) {