34 #include <system_error>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <sys/fcntl.h>
49 using namespace scc::net;
53 return os.write(sa.str().c_str(), sa.str().size());
56 SocketBase::SocketBase(
int domain,
int stype,
int proto) : m_fd{-1}
58 m_fd = ::socket(domain, stype, proto);
63 throw std::system_error(errno, std::system_category(), st.str());
67 SocketBase::~SocketBase()
81 void SocketBase::reset(
int domain,
int stype,
int proto)
85 m_fd = ::socket(domain, stype, proto);
89 st <<
"socket() from reset()";
90 throw std::system_error(errno, std::system_category(), st.str());
98 socklen_t len =
sizeof(x);
99 if (::getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &x, &len))
101 std::stringstream st;
102 st <<
"getsockopt(SO_ERROR)";
103 throw std::system_error(errno, std::system_category(), st.str());
105 return std::error_code(x, std::system_category());
112 socklen_t len =
sizeof(x);
113 if (::setsockopt(m_fd, SOL_SOCKET, SO_RCVBUF, &x, len))
115 std::stringstream st;
116 st <<
"setsockopt(SO_RCVBUF)";
117 throw std::system_error(errno, std::system_category(), st.str());
125 socklen_t len =
sizeof(x);
126 if (::getsockopt(m_fd, SOL_SOCKET, SO_RCVBUF, &x, &len))
128 std::stringstream st;
129 st <<
"getsockopt(SO_RCVBUF)";
130 throw std::system_error(errno, std::system_category(), st.str());
139 socklen_t len =
sizeof(x);
140 if (::setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &x, len))
142 std::stringstream st;
143 st <<
"setsockopt(SO_SNDBUF)";
144 throw std::system_error(errno, std::system_category(), st.str());
152 socklen_t len =
sizeof(x);
153 if (::getsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &x, &len))
155 std::stringstream st;
156 st <<
"getsockopt(SO_SNDBUF)";
157 throw std::system_error(errno, std::system_category(), st.str());
166 socklen_t len =
sizeof(x);
167 if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &x, len))
169 std::stringstream st;
170 st <<
"setsockopt(SO_REUSEADDR)";
171 throw std::system_error(errno, std::system_category(), st.str());
179 socklen_t len =
sizeof(x);
180 if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEPORT, &x, len))
182 std::stringstream st;
183 st <<
"setsockopt(SO_REUSEPORT)";
184 throw std::system_error(errno, std::system_category(), st.str());
190 int flags = ::fcntl(m_fd, F_GETFL, 0);
193 std::stringstream st;
194 st <<
"fcntl(F_GETFL)";
195 throw std::system_error(errno, std::system_category(), st.str());
199 if (::fcntl(m_fd, F_SETFL, flags | O_NONBLOCK) == -1)
201 std::stringstream st;
202 st <<
"fcntl(F_SETFL)";
203 throw std::system_error(errno, std::system_category(), st.str());
208 if (::fcntl(m_fd, F_SETFL, flags & ~O_NONBLOCK) == -1)
210 std::stringstream st;
211 st <<
"fcntl(F_SETFL)";
212 throw std::system_error(errno, std::system_category(), st.str());
220 x.tv_sec = t.count() / 1000;
221 x.tv_usec = (t.count() % 1000) * 1000;
223 socklen_t len =
sizeof(x);
224 if (::setsockopt(m_fd, SOL_SOCKET, SO_SNDTIMEO, &x, len))
226 std::stringstream st;
227 st <<
"setsockopt(SO_SNDTIMEO)";
228 throw std::system_error(errno, std::system_category(), st.str());
235 x.tv_sec = t.count() / 1000;
236 x.tv_usec = (t.count() % 1000) * 1000;
238 socklen_t len =
sizeof(x);
239 if (::setsockopt(m_fd, SOL_SOCKET, SO_RCVTIMEO, &x, len))
241 std::stringstream st;
242 st <<
"setsockopt(SO_RCVTIMEO)";
243 throw std::system_error(errno, std::system_category(), st.str());
254 sz = ::recv(m_fd, loc, len, 0);
256 while (sz == -1 && errno == EINTR);
260 ec.assign(errno, std::system_category());
270 size_t sz =
recv(loc, len, ec);
273 std::stringstream st;
275 throw std::system_error(ec, st.str());
287 sz = ::send(m_fd, loc, len, MSG_NOSIGNAL);
289 while (sz == -1 && errno == EINTR);
293 ec.assign(errno, std::system_category());
303 size_t sz =
send(loc, len, ec);
306 std::stringstream st;
308 throw std::system_error(ec, st.str());
315 if (::
bind(m_fd, a, a.len()))
317 std::stringstream st;
319 throw std::system_error(errno, std::system_category(), st.str());
323 void SocketBase::get_sockaddr(sockaddr& a)
325 socklen_t len =
sizeof(a);
326 if (::getsockname(m_fd, &a, &len))
328 std::stringstream st;
329 st <<
"getsockname()";
330 throw std::system_error(errno, std::system_category(), st.str());
336 if (::
listen(
fd(), max_connection_backlog))
338 std::stringstream st;
340 throw std::system_error(errno, std::system_category(), st.str());
349 sockaddr* sa =
nullptr;
350 socklen_t* sp =
nullptr;
362 nfd = ::accept(fd(), sa, sp);
364 while (nfd == -1 && errno == EINTR);
368 ec.assign(errno, std::system_category());
384 ret = ::connect(fd(), p, p.len());
386 while (ret == -1 && errno == EINTR);
390 ec.assign(errno, std::system_category());
403 std::stringstream st;
405 throw std::system_error(ec, st.str());
419 std::stringstream st;
421 throw std::system_error(errno, std::system_category(), st.str());
425 UdpSocket::UdpSocket(
int domain,
int stype,
int proto) :
SocketBase(domain, stype, proto) { }
431 socklen_t alen = a.len();
436 sz = ::recvfrom(fd(), loc, len, 0, a, &alen);
438 while (sz == -1 && errno == EINTR);
442 ec.assign(errno, std::system_category());
447 assert(alen <= a.len());
456 size_t sz =
recv(loc, len, a, ec);
459 std::stringstream st;
461 throw std::system_error(ec, st.str());
473 sz = ::sendto(fd(), loc, len, 0, a, a.len());
475 while (sz == -1 && errno == EINTR);
479 ec.assign(errno, std::system_category());
489 size_t sz =
send(loc, len, a, ec);
492 std::stringstream st;
494 throw std::system_error(ec, st.str());
504 r = ::ioctl(
fd(), FIONREAD, &v);
506 while (r == -1 && errno == EINTR);
509 std::stringstream st;
510 st <<
"ioctl(FIONREAD)";
511 throw std::system_error(errno, std::system_category(), st.str());
Socket address base class.
int fd() const
Return the underlying socket handle.
unsigned send_bufsize()
Get total send buffer size including overhead.
std::error_code error_code()
Get the current error code (status).
void recv_timeout(std::chrono::milliseconds)
Set the receive timeout.
size_t recv(void *loc, size_t len)
Receive bytes, throwing an exception on error.
void send_timeout(std::chrono::milliseconds)
Set the send timeout.
void non_blocking(bool b=true)
Set the socket non-blocking.
size_t send(const void *loc, size_t len)
Send bytes, throwing an exception on error.
void bind(const SockaddrBase &)
Bind an address to the socket.
void reuse_addr(bool r=true)
Set address reusable.
unsigned recv_bufsize()
Get total receive buffer size including overhead.
void reuse_port(bool r=true)
Set port reusable.
void close()
Close the socket.
void shutdown()
Shutdown the connection; no further reads or writes will be allowed.
void listen(int maxConnections=10)
Set to accept connections.
int accept(sockaddr *, int len, std::error_code &) noexcept
Accept a connection.
void connect(SockaddrBase &)
Connect to a socket address.
size_t recv(void *loc, size_t len, SockaddrBase &s)
Receive bytes (a datagram), setting the socket address of the peer.
size_t send(const void *loc, size_t len, const SockaddrBase &d)
Send bytes (a datagram) to a peer address.
size_t recv_next()
Return the number of bytes available to read (the size of the next datagram).
int safe_close(int fd)
Signal safe close.
Signal-safe C library wrapper.
std::ostream & operator<<(std::ostream &os, const SockaddrBase &sa)
Helper to print socket address to output stream.
Low-level tcp and udp sockets.