#include <fcntl.h>
#include <stdexcept>
-#include <boost/utility.hpp>
#include <csignal>
#include "namespaces.hh"
#include "noinitvector.hh"
using ProtocolType = int; //!< Supported protocol types
//! Representation of a Socket and many of the Berkeley functions available
-class Socket : public boost::noncopyable
+class Socket
{
public:
- Socket(int fd) :
- d_socket(fd)
+ Socket(const Socket&) = delete;
+ Socket& operator=(const Socket&) = delete;
+
+ Socket(int socketDesc) :
+ d_socket(socketDesc)
{
}
//! Construct a socket of specified address family and socket type.
- Socket(int af, int st, ProtocolType pt = 0)
+ Socket(int addressFamily, int socketType, ProtocolType protocolType = 0) :
+ d_socket(socket(addressFamily, socketType, protocolType))
{
- if ((d_socket = socket(af, st, pt)) < 0)
+ if (d_socket < 0) {
throw NetworkError(stringerror());
+ }
setCloseOnExec(d_socket);
}
}
//! If the socket is capable of doing so, this function will wait for a connection
- std::unique_ptr<Socket> accept()
+ [[nodiscard]] std::unique_ptr<Socket> accept() const
{
- struct sockaddr_in remote;
+ sockaddr_in remote{};
socklen_t remlen = sizeof(remote);
memset(&remote, 0, sizeof(remote));
- int s = ::accept(d_socket, reinterpret_cast<sockaddr*>(&remote), &remlen);
- if (s < 0) {
- if (errno == EAGAIN)
+ int sock = ::accept(d_socket, reinterpret_cast<sockaddr*>(&remote), &remlen); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
+ if (sock < 0) {
+ if (errno == EAGAIN) {
return nullptr;
+ }
throw NetworkError("Accepting a connection: " + stringerror());
}
- return std::make_unique<Socket>(s);
+ return std::make_unique<Socket>(sock);
}
//! Get remote address
- bool getRemote(ComboAddress& remote)
+ bool getRemote(ComboAddress& remote) const
{
socklen_t remotelen = sizeof(remote);
- return (getpeername(d_socket, reinterpret_cast<struct sockaddr*>(&remote), &remotelen) >= 0);
+ return getpeername(d_socket, reinterpret_cast<struct sockaddr*>(&remote), &remotelen) >= 0; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): it's the API
}
//! Check remote address against netmaskgroup ng
- bool acl(const NetmaskGroup& ng)
+ [[nodiscard]] bool acl(const NetmaskGroup& netmaskGroup) const
{
ComboAddress remote;
- if (getRemote(remote))
- return ng.match(remote);
+ if (getRemote(remote)) {
+ return netmaskGroup.match(remote);
+ }
return false;
}
//! Set the socket to non-blocking
- void setNonBlocking()
+ void setNonBlocking() const
{
::setNonBlocking(d_socket);
}
//! Set the socket to blocking
- void setBlocking()
+ void setBlocking() const
{
::setBlocking(d_socket);
}
- void setReuseAddr()
+ void setReuseAddr() const
{
try {
::setReuseAddr(d_socket);
}
//! Bind the socket to a specified endpoint
- void bind(const ComboAddress& local, bool reuseaddr = true)
+ void bind(const ComboAddress& local, bool reuseaddr = true) const
{
int tmp = 1;
- if (reuseaddr && setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&tmp), sizeof tmp) < 0)
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (reuseaddr && setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&tmp), sizeof tmp) < 0) {
throw NetworkError("Setsockopt failed: " + stringerror());
-
- if (::bind(d_socket, reinterpret_cast<const struct sockaddr*>(&local), local.getSocklen()) < 0)
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ if (::bind(d_socket, reinterpret_cast<const struct sockaddr*>(&local), local.getSocklen()) < 0) {
throw NetworkError("While binding: " + stringerror());
+ }
}
//! Connect the socket to a specified endpoint
- void connect(const ComboAddress& ep, int timeout = 0)
+ void connect(const ComboAddress& address, int timeout = 0) const
{
- SConnectWithTimeout(d_socket, ep, timeval{timeout, 0});
+ SConnectWithTimeout(d_socket, address, timeval{timeout, 0});
}
//! For datagram sockets, receive a datagram and learn where it came from
/** For datagram sockets, receive a datagram and learn where it came from
\param dgram Will be filled with the datagram
\param ep Will be filled with the origin of the datagram */
- void recvFrom(string& dgram, ComboAddress& remote)
+ void recvFrom(string& dgram, ComboAddress& remote) const
{
socklen_t remlen = sizeof(remote);
if (dgram.size() < s_buflen) {
dgram.resize(static_cast<size_t>(bytes));
}
- bool recvFromAsync(PacketBuffer& dgram, ComboAddress& remote)
+ bool recvFromAsync(PacketBuffer& dgram, ComboAddress& remote) const
{
socklen_t remlen = sizeof(remote);
if (dgram.size() < s_buflen) {
if (errno != EAGAIN) {
throw NetworkError("After async recvfrom: " + stringerror());
}
- else {
- return false;
- }
+ return false;
}
dgram.resize(static_cast<size_t>(bytes));
return true;
}
//! For datagram sockets, send a datagram to a destination
- void sendTo(const char* msg, size_t len, const ComboAddress& remote)
+ void sendTo(const char* msg, size_t len, const ComboAddress& remote) const
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
if (sendto(d_socket, msg, len, 0, reinterpret_cast<const sockaddr*>(&remote), remote.getSocklen()) < 0) {
}
//! For connected datagram sockets, send a datagram
- void send(const std::string& msg)
+ void send(const std::string& msg) const
{
if (::send(d_socket, msg.data(), msg.size(), 0) < 0) {
throw NetworkError("After send: " + stringerror());
/** For datagram sockets, send a datagram to a destination
\param dgram The datagram
\param remote The intended destination of the datagram */
- void sendTo(const string& dgram, const ComboAddress& remote)
+ void sendTo(const string& dgram, const ComboAddress& remote) const
{
sendTo(dgram.data(), dgram.length(), remote);
}
//! Write this data to the socket, taking care that all bytes are written out
- void writen(const string& data)
+ void writen(const string& data) const
{
- if (data.empty())
+ if (data.empty()) {
return;
+ }
size_t toWrite = data.length();
- ssize_t res;
- const char* ptr = data.c_str();
+ const char* ptr = data.data();
do {
- res = ::send(d_socket, ptr, toWrite, 0);
- if (res < 0)
+ auto res = ::send(d_socket, ptr, toWrite, 0);
+ if (res < 0) {
throw NetworkError("Writing to a socket: " + stringerror());
- if (!res)
+ }
+ if (res == 0) {
throw NetworkError("EOF on socket");
+ }
toWrite -= static_cast<size_t>(res);
- ptr += static_cast<size_t>(res);
- } while (toWrite);
+ ptr += static_cast<size_t>(res); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ } while (toWrite > 0);
}
//! tries to write toWrite bytes from ptr to the socket
\param ptr Location to write from
\param toWrite number of bytes to try
*/
- size_t tryWrite(const char* ptr, size_t toWrite)
+ size_t tryWrite(const char* ptr, size_t toWrite) const
{
- ssize_t res;
- res = ::send(d_socket, ptr, toWrite, 0);
- if (res == 0)
+ auto res = ::send(d_socket, ptr, toWrite, 0);
+ if (res == 0) {
throw NetworkError("EOF on writing to a socket");
-
- if (res > 0)
+ }
+ if (res > 0) {
return res;
+ }
- if (errno == EAGAIN)
+ if (errno == EAGAIN) {
return 0;
+ }
throw NetworkError("Writing to a socket: " + stringerror());
}
//! Writes toWrite bytes from ptr to the socket
/** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */
- size_t write(const char* ptr, size_t toWrite)
+ size_t write(const char* ptr, size_t toWrite) const
{
- ssize_t res;
- res = ::send(d_socket, ptr, toWrite, 0);
+ auto res = ::send(d_socket, ptr, toWrite, 0);
if (res < 0) {
throw NetworkError("Writing to a socket: " + stringerror());
}
return res;
}
- void writenWithTimeout(const void* buffer, size_t n, int timeout)
+ void writenWithTimeout(const void* buffer, size_t n, int timeout) const
{
size_t bytes = n;
- const char* ptr = reinterpret_cast<const char*>(buffer);
- ssize_t ret;
- while (bytes) {
- ret = ::write(d_socket, ptr, bytes);
+ const char* ptr = static_cast<const char*>(buffer);
+
+ while (bytes > 0) {
+ auto ret = ::write(d_socket, ptr, bytes);
if (ret < 0) {
if (errno == EAGAIN) {
ret = waitForRWData(d_socket, false, timeout, 0);
- if (ret < 0)
+ if (ret < 0) {
throw NetworkError("Waiting for data write");
- if (!ret)
+ }
+ if (ret == 0) {
throw NetworkError("Timeout writing data");
+ }
continue;
}
- else
- throw NetworkError("Writing data: " + stringerror());
+ throw NetworkError("Writing data: " + stringerror());
}
- if (!ret) {
+ if (ret == 0) {
throw NetworkError("Did not fulfill TCP write due to EOF");
}
- ptr += static_cast<size_t>(ret);
+ ptr += static_cast<size_t>(ret); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
bytes -= static_cast<size_t>(ret);
}
}
//! reads one character from the socket
- int getChar()
+ [[nodiscard]] int getChar() const
{
- char c;
+ char character{};
- ssize_t res = ::recv(d_socket, &c, 1, 0);
- if (res)
- return c;
+ ssize_t res = ::recv(d_socket, &character, 1, 0);
+ if (res == 0) {
+ return character;
+ }
return -1;
}
- void getline(string& data)
+ void getline(string& data) const
{
- data = "";
- int c;
- while ((c = getChar()) != -1) {
- data += (char)c;
- if (c == '\n')
+ data.clear();
+ while (true) {
+ int character = getChar();
+ if (character == -1) {
break;
+ }
+ data += (char)character;
+ if (character == '\n') {
+ break;
+ }
}
}
void read(string& data)
{
d_buffer.resize(s_buflen);
- ssize_t res = ::recv(d_socket, &d_buffer[0], s_buflen, 0);
- if (res < 0)
+ ssize_t res = ::recv(d_socket, d_buffer.data(), s_buflen, 0);
+ if (res < 0) {
throw NetworkError("Reading from a socket: " + stringerror());
+ }
data.assign(d_buffer, 0, static_cast<size_t>(res));
}
//! Reads a block of data from the socket to a block of memory
- size_t read(char* buffer, size_t bytes)
+ size_t read(char* buffer, size_t bytes) const
{
- ssize_t res = ::recv(d_socket, buffer, bytes, 0);
- if (res < 0)
+ auto res = ::recv(d_socket, buffer, bytes, 0);
+ if (res < 0) {
throw NetworkError("Reading from a socket: " + stringerror());
+ }
return static_cast<size_t>(res);
}
* available. Be aware that this does _NOT_ handle partial reads
* for you.
*/
- ssize_t readWithTimeout(char* buffer, size_t n, int timeout)
+ size_t readWithTimeout(char* buffer, size_t n, int timeout) const
{
int err = waitForRWData(d_socket, true, timeout, 0);
- if (err == 0)
+ if (err == 0) {
throw NetworkError("timeout reading");
- if (err < 0)
+ }
+ if (err < 0) {
throw NetworkError("nonblocking read failed: " + stringerror());
+ }
return read(buffer, n);
}
//! Sets the socket to listen with a default listen backlog of 10 pending connections
- void listen(unsigned int length = 10)
+ void listen(int length = 10) const
{
- if (::listen(d_socket, length) < 0)
+ if (::listen(d_socket, length) < 0) {
throw NetworkError("Setting socket to listen: " + stringerror());
+ }
}
//! Returns the internal file descriptor of the socket
- int getHandle() const
+ [[nodiscard]] int getHandle() const
{
return d_socket;
}