jsocketpp 1.0
A cross-platform C++20 socket library.
Loading...
Searching...
No Matches
Socket.hpp
Go to the documentation of this file.
1
8
9#pragma once
10
11#include "BufferView.hpp"
12#include "SocketException.hpp"
13#include "common.hpp"
14
15#include <array>
16#include <limits>
17#include <optional>
18#include <span>
19#include <string_view>
20#include <type_traits>
21#include <vector>
22
24
25namespace jsocketpp
26{
27
90class Socket
91{
104 friend class ServerSocket;
105
106 protected:
136 Socket(SOCKET client, const sockaddr_storage& addr, socklen_t len, std::size_t recvBufferSize,
137 std::size_t sendBufferSize, std::size_t internalBufferSize);
138
139 public:
161 Socket() = delete;
162
198 Socket(std::string_view host, Port port, std::optional<std::size_t> recvBufferSize = std::nullopt,
199 std::optional<std::size_t> sendBufferSize = std::nullopt,
200 std::optional<std::size_t> internalBufferSize = std::nullopt);
201
227 Socket(const Socket& rhs) = delete; //-Weffc++
228
257 Socket(Socket&& rhs) noexcept
258 : _sockFd(rhs._sockFd), _remoteAddr(rhs._remoteAddr), _remoteAddrLen(rhs._remoteAddrLen),
259 _cliAddrInfo(rhs._cliAddrInfo), _selectedAddrInfo(rhs._selectedAddrInfo),
260 _internalBuffer(std::move(rhs._internalBuffer))
261 {
262 rhs._sockFd = INVALID_SOCKET;
263 rhs._cliAddrInfo = nullptr;
264 rhs._selectedAddrInfo = nullptr;
265 }
266
294 Socket& operator=(const Socket& rhs) = delete; //-Weffc++
295
328 Socket& operator=(Socket&& rhs) noexcept
329 {
330 if (this != &rhs)
331 {
332 if (this->_sockFd != INVALID_SOCKET)
333 {
334 if (CloseSocket(this->_sockFd))
335 std::cerr << "closesocket() failed: " << SocketErrorMessage(GetSocketError()) << ": "
336 << GetSocketError() << std::endl;
337 }
338 if (_cliAddrInfo)
339 {
340 freeaddrinfo(_cliAddrInfo);
341 _cliAddrInfo = nullptr;
342 }
343 _sockFd = rhs._sockFd;
344 _remoteAddr = rhs._remoteAddr;
345 _remoteAddrLen = rhs._remoteAddrLen;
346 _cliAddrInfo = rhs._cliAddrInfo;
347 _selectedAddrInfo = rhs._selectedAddrInfo;
348 _internalBuffer = std::move(rhs._internalBuffer);
349 rhs._sockFd = INVALID_SOCKET;
350 rhs._cliAddrInfo = nullptr;
351 rhs._selectedAddrInfo = nullptr;
352 }
353 return *this;
354 }
355
375 ~Socket() noexcept;
376
407 std::string getRemoteSocketAddress(bool convertIPv4Mapped = true) const;
408
478 void connect(int timeoutMillis = -1) const;
479
553 template <typename T> T read()
554 {
555 static_assert(std::is_trivially_copyable_v<T>, "Socket::read<T>() only supports trivially copyable types");
556 T r;
557 std::array<char, sizeof(T)> buffer;
558 size_t totalRead = 0;
559 size_t remaining = sizeof(T);
560
561 while (remaining > 0)
562 {
563 const auto len = recv(this->_sockFd, buffer.data() + totalRead,
564#ifdef _WIN32
565 static_cast<int>(remaining),
566#else
567 remaining,
568#endif
569 0);
570 if (len == SOCKET_ERROR)
572 if (len == 0)
573 throw SocketException(0, "Connection closed by remote host.");
574
575 totalRead += len;
576 remaining -= len;
577 }
578 std::memcpy(&r, buffer.data(), sizeof(T));
579 return r;
580 }
581
631 std::string readExact(std::size_t n) const;
632
682 std::string readUntil(char delimiter, std::size_t maxLen = 8192, bool includeDelimiter = true) const;
683
713 std::string readLine(const std::size_t maxLen = 8192, const bool includeDelimiter = true) const
714 {
715 return readUntil('\n', maxLen, includeDelimiter);
716 }
717
774 std::string readAtMost(std::size_t n) const;
775
819 std::size_t readInto(void* buffer, const std::size_t len) const { return readIntoInternal(buffer, len, false); }
820
872 std::size_t readIntoExact(void* buffer, const std::size_t len) const { return readIntoInternal(buffer, len, true); }
873
933 std::string readAtMostWithTimeout(std::size_t n, int timeoutMillis) const;
934
1001 template <typename T> std::string readPrefixed()
1002 {
1003 static_assert(std::is_integral_v<T> && std::is_trivially_copyable_v<T>,
1004 "Prefix type must be a trivially copyable integral type");
1005
1006 T netLen = read<T>();
1007 T length = net::fromNetwork(netLen);
1008 return readExact(static_cast<std::size_t>(length));
1009 }
1010
1074 template <typename T> std::string readPrefixed(const std::size_t maxPayloadLen)
1075 {
1076 static_assert(std::is_integral_v<T> && std::is_trivially_copyable_v<T>,
1077 "Prefix type must be a trivially copyable integral type");
1078
1079 T netLen = read<T>();
1080 T length = net::fromNetwork(netLen);
1081
1082 const auto payloadLen = static_cast<std::size_t>(length);
1083 if (payloadLen > maxPayloadLen)
1084 {
1085 throw SocketException(0, "readPrefixed: Prefix length " + std::to_string(payloadLen) +
1086 " exceeds maximum allowed payload length of " + std::to_string(maxPayloadLen));
1087 }
1088
1089 return readExact(payloadLen);
1090 }
1091
1138 std::string readAvailable() const;
1139
1184 std::size_t readIntoAvailable(void* buffer, std::size_t bufferSize) const;
1185
1219 std::size_t readv(std::span<BufferView> buffers) const;
1220
1252 std::size_t readvAll(std::span<BufferView> buffers) const;
1253
1288 std::size_t readvAllWithTotalTimeout(std::span<BufferView> buffers, int timeoutMillis) const;
1289
1325 std::size_t readvAtMostWithTimeout(std::span<BufferView> buffers, int timeoutMillis) const;
1326
1365 std::string peek(std::size_t n) const;
1366
1389 void discard(std::size_t n, std::size_t chunkSize = 1024) const;
1390
1429 void close();
1430
1498 void shutdown(ShutdownMode how) const;
1499
1547 [[nodiscard]] size_t write(std::string_view message) const;
1548
1597 size_t writeAll(std::string_view message) const;
1598
1654 template <typename T> std::size_t writePrefixed(const std::string& payload)
1655 {
1656 static_assert(std::is_integral_v<T> && std::is_trivially_copyable_v<T>,
1657 "Prefix type must be a trivially copyable integral type");
1658
1659 const std::size_t payloadSize = payload.size();
1660
1661 // Put parentheses around the `max` function name due to a collision with
1662 // a macro defined in windows.h. See:
1663 // https://stackoverflow.com/a/13420838/3049315
1664 // Another alternative would be to define `NOMINMAX` before including windows.h
1665 // such as in CMake when compiling the target library
1666 if (payloadSize > static_cast<std::size_t>((std::numeric_limits<T>::max)()))
1667 {
1668 throw SocketException(0, "writePrefixed: Payload size " + std::to_string(payloadSize) +
1669 " exceeds maximum encodable size for prefix type");
1670 }
1671
1672 T len = net::toNetwork(static_cast<T>(payloadSize));
1673
1674 // Write the length prefix
1675 const std::size_t prefixSent = writeAll(std::string_view(reinterpret_cast<const char*>(&len), sizeof(T)));
1676
1677 // Then write the payload
1678 const std::size_t dataSent = writeAll(payload);
1679
1680 return prefixSent + dataSent;
1681 }
1682
1734 template <typename T> std::size_t writePrefixed(const void* data, std::size_t len) const
1735 {
1736 static_assert(std::is_integral_v<T> && std::is_trivially_copyable_v<T>,
1737 "Prefix type must be a trivially copyable integral type");
1738
1739 if (!data && len > 0)
1740 throw SocketException(0, "writePrefixed: Null data pointer with non-zero length");
1741
1742 if (len > static_cast<std::size_t>((std::numeric_limits<T>::max)()))
1743 {
1744 throw SocketException(0, "writePrefixed: Payload length exceeds capacity of prefix type");
1745 }
1746
1747 T prefix = net::toNetwork(static_cast<T>(len));
1748
1749 // Send prefix
1750 writeAll(std::string_view(reinterpret_cast<const char*>(&prefix), sizeof(T)));
1751
1752 // Send payload
1753 if (len > 0)
1754 {
1755 writeAll(std::string_view(static_cast<const char*>(data), len));
1756 }
1757
1758 return sizeof(T) + len;
1759 }
1760
1798 std::size_t writev(std::span<const std::string_view> buffers) const;
1799
1836 std::size_t writevAll(std::span<const std::string_view> buffers) const;
1837
1873 std::size_t writeAtMostWithTimeout(std::string_view data, int timeoutMillis) const;
1874
1905 std::size_t writeFrom(const void* data, std::size_t len) const;
1906
1937 std::size_t writeFromAll(const void* data, std::size_t len) const;
1938
1973 std::size_t writeWithTotalTimeout(std::string_view data, int timeoutMillis) const;
1974
2014 std::size_t writevWithTotalTimeout(std::span<const std::string_view> buffers, int timeoutMillis) const;
2015
2047 std::size_t writevFrom(std::span<const BufferView> buffers) const;
2048
2083 std::size_t writevFromAll(std::span<BufferView> buffers) const;
2084
2120 std::size_t writevFromWithTotalTimeout(std::span<BufferView> buffers, int timeoutMillis) const;
2121
2168 void setReceiveBufferSize(std::size_t size);
2169
2216 void setSendBufferSize(std::size_t size);
2217
2263 [[nodiscard]] int getReceiveBufferSize() const;
2264
2310 [[nodiscard]] int getSendBufferSize() const;
2311
2350 void setInternalBufferSize(std::size_t newLen);
2351
2387 [[nodiscard]] bool isValid() const noexcept { return this->_sockFd != INVALID_SOCKET; }
2388
2442 void setNonBlocking(bool nonBlocking) const;
2443
2497 [[nodiscard]] bool getNonBlocking() const;
2498
2555 void setSoTimeout(int millis, bool forRead = true, bool forWrite = true);
2556
2565 bool waitReady(bool forWrite, int timeoutMillis) const;
2566
2600 bool isConnected() const;
2601
2635 void enableNoDelay(bool enable);
2636
2671 void enableKeepAlive(bool enable);
2672
2683 static std::string addressToString(const sockaddr_storage& addr);
2684
2691 static void stringToAddress(const std::string& str, sockaddr_storage& addr);
2692
2710 void setOption(int level, int optName, int value);
2711
2728 [[nodiscard]] int getOption(int level, int optName) const;
2729
2730 protected:
2795 std::size_t readIntoInternal(void* buffer, std::size_t len, bool exact = false) const;
2796
2819 void cleanupAndThrow(int errorCode);
2820
2821 private:
2823 sockaddr_storage _remoteAddr;
2825 mutable socklen_t _remoteAddrLen = 0;
2826 addrinfo* _cliAddrInfo = nullptr;
2827 addrinfo* _selectedAddrInfo = nullptr;
2828 std::vector<char> _internalBuffer;
2829};
2830
2879template <> inline std::string Socket::read()
2880{
2881 const auto len = recv(_sockFd, _internalBuffer.data(),
2882#ifdef _WIN32
2883 static_cast<int>(_internalBuffer.size()),
2884#else
2885 _internalBuffer.size(),
2886#endif
2887 0);
2888 if (len == SOCKET_ERROR)
2890 if (len == 0)
2891 throw SocketException(0, "Connection closed by remote host.");
2892 return {_internalBuffer.data(), static_cast<size_t>(len)};
2893}
2894
2895} // namespace jsocketpp
Represents a raw writable memory region for scatter/gather I/O.
Exception class for socket-related errors in jsocketpp.
Represents socket-related errors in the jsocketpp library.
Definition SocketException.hpp:58
std::vector< char > _internalBuffer
Internal buffer for read operations, not thread-safe.
Definition Socket.hpp:2828
friend class ServerSocket
Grants ServerSocket access to private members.
Definition Socket.hpp:104
void enableNoDelay(bool enable)
Enable or disable TCP_NODELAY (Nagle's algorithm) on the socket.
Definition Socket.cpp:494
static void stringToAddress(const std::string &str, sockaddr_storage &addr)
Convert a string (ip:port) to sockaddr_storage.
Definition Socket.cpp:553
bool waitReady(bool forWrite, int timeoutMillis) const
Wait for the socket to be ready for reading or writing.
Definition Socket.cpp:413
bool isConnected() const
Check if the socket is still connected (TCP only).
Definition Socket.cpp:448
SOCKET _sockFd
Underlying socket file descriptor.
Definition Socket.hpp:2822
socklen_t _remoteAddrLen
Length of remote address (for recvfrom/recvmsg)
Definition Socket.hpp:2825
void enableKeepAlive(bool enable)
Enable or disable SO_KEEPALIVE on the socket.
Definition Socket.cpp:503
int getOption(int level, int optName) const
Get the current value of a socket option at the specified level.
Definition Socket.cpp:597
addrinfo * _selectedAddrInfo
Selected address info for connection.
Definition Socket.hpp:2827
addrinfo * _cliAddrInfo
Address info for connection (from getaddrinfo)
Definition Socket.hpp:2826
static std::string addressToString(const sockaddr_storage &addr)
Convert an address and port to a string using getnameinfo.
Definition Socket.cpp:511
sockaddr_storage _remoteAddr
(portability)
Definition Socket.hpp:2823
void setOption(int level, int optName, int value)
Set a socket option at the specified level.
Definition Socket.cpp:585
Common platform and utility includes for jsocketpp.
std::uint16_t Port
Type alias representing a TCP or UDP port number (1–65535).
Definition common.hpp:315
constexpr std::size_t DefaultBufferSize
Default internal buffer size (in bytes) for TCP socket read operations.
Definition common.hpp:352
void setReceiveBufferSize(std::size_t size)
Sets the socket's receive buffer size (SO_RCVBUF).
Definition Socket.cpp:315
Socket & operator=(Socket &&rhs) noexcept
Move assignment operator that transfers socket ownership safely.
Definition Socket.hpp:328
std::size_t writeAtMostWithTimeout(std::string_view data, int timeoutMillis) const
Performs a best-effort write with a total timeout.
Definition Socket.cpp:1005
void setSendBufferSize(std::size_t size)
Sets the socket's send buffer size (SO_SNDBUF).
Definition Socket.cpp:321
~Socket() noexcept
Destructs the Socket object, closing connections and freeing resources.
Definition Socket.cpp:164
std::size_t writePrefixed(const std::string &payload)
Writes a length-prefixed payload using a fixed-size prefix type.
Definition Socket.hpp:1654
std::string readLine(const std::size_t maxLen=8192, const bool includeDelimiter=true) const
Reads a line terminated by ' ' from the socket.
Definition Socket.hpp:713
std::string readAtMostWithTimeout(std::size_t n, int timeoutMillis) const
Performs a best-effort read up to n bytes, with a maximum timeout.
Definition Socket.cpp:746
std::string readUntil(char delimiter, std::size_t maxLen=8192, bool includeDelimiter=true) const
Reads data from the socket until a specified delimiter character.
Definition Socket.cpp:649
std::string readExact(std::size_t n) const
Read exactly n bytes from the socket into a string.
Definition Socket.cpp:616
std::size_t writevFromWithTotalTimeout(std::span< BufferView > buffers, int timeoutMillis) const
Writes all raw memory buffers fully within a timeout using scatter I/O.
Definition Socket.cpp:1423
void setInternalBufferSize(std::size_t newLen)
Sets the size of the internal read buffer used for string operations.
Definition Socket.cpp:336
Socket & operator=(const Socket &rhs)=delete
Copy assignment operator (deleted) for Socket class.
int getReceiveBufferSize() const
Get the socket's receive buffer size (SO_RCVBUF).
Definition Socket.cpp:326
std::string peek(std::size_t n) const
Peeks at incoming data without consuming it.
Definition Socket.cpp:854
void connect(int timeoutMillis=-1) const
Establishes a TCP connection to the remote host with optional timeout control.
Definition Socket.cpp:82
std::size_t writevFrom(std::span< const BufferView > buffers) const
Writes multiple raw memory regions using vectorized I/O.
Definition Socket.cpp:1350
std::size_t writeFromAll(const void *data, std::size_t len) const
Writes all bytes from a raw memory buffer, retrying until complete.
Definition Socket.cpp:1060
std::size_t readvAtMostWithTimeout(std::span< BufferView > buffers, int timeoutMillis) const
Attempts a single vectorized read into multiple buffers with a timeout.
Definition Socket.cpp:1336
void setNonBlocking(bool nonBlocking) const
Set the socket to non-blocking or blocking mode.
Definition Socket.cpp:342
bool getNonBlocking() const
Check if the socket is currently in non-blocking mode.
Definition Socket.cpp:361
void discard(std::size_t n, std::size_t chunkSize=1024) const
Discards exactly n bytes from the socket by reading and discarding them.
Definition Socket.cpp:883
std::size_t readIntoInternal(void *buffer, std::size_t len, bool exact=false) const
Reads data from the socket into a user-supplied buffer.
Definition Socket.cpp:712
void close()
Closes the socket connection and releases associated resources.
Definition Socket.cpp:179
std::string readAvailable() const
Reads all bytes currently available on the socket without blocking.
Definition Socket.cpp:775
std::size_t writevFromAll(std::span< BufferView > buffers) const
Writes all raw memory regions fully using scatter/gather I/O.
Definition Socket.cpp:1380
std::string readAtMost(std::size_t n) const
Reads up to n bytes from the socket into a string.
Definition Socket.cpp:686
std::size_t writevAll(std::span< const std::string_view > buffers) const
Writes all buffers fully using vectorized I/O with automatic retry on partial sends.
Definition Socket.cpp:963
size_t write(std::string_view message) const
Writes data to the socket, handling partial writes.
Definition Socket.cpp:279
std::size_t writevWithTotalTimeout(std::span< const std::string_view > buffers, int timeoutMillis) const
Writes all buffers fully within a total timeout using vectorized I/O.
Definition Socket.cpp:1142
std::size_t readv(std::span< BufferView > buffers) const
Performs a vectorized read into multiple buffers using a single system call.
Definition Socket.cpp:1198
std::string getRemoteSocketAddress(bool convertIPv4Mapped=true) const
Get the remote peer's address and port as a formatted string.
Definition Socket.cpp:243
Socket(SOCKET client, const sockaddr_storage &addr, socklen_t len, std::size_t recvBufferSize, std::size_t sendBufferSize, std::size_t internalBufferSize)
Protected constructor used internally to create Socket objects for accepted client connections.
Definition Socket.cpp:12
std::size_t writeWithTotalTimeout(std::string_view data, int timeoutMillis) const
Writes the full payload with a total timeout across all retries.
Definition Socket.cpp:1095
T read()
Reads a fixed-size trivially copyable value of type T from the socket.
Definition Socket.hpp:553
void shutdown(ShutdownMode how) const
Shutdown specific communication aspects of the socket.
Definition Socket.cpp:196
std::size_t writePrefixed(const void *data, std::size_t len) const
Writes a binary payload prefixed with its length using a fixed-size integer type.
Definition Socket.hpp:1734
void setSoTimeout(int millis, bool forRead=true, bool forWrite=true)
Set timeout for socket send and/or receive operations.
Definition Socket.cpp:381
std::string readPrefixed()
Reads a length-prefixed payload using a fixed-size prefix type.
Definition Socket.hpp:1001
std::size_t writeFrom(const void *data, std::size_t len) const
Writes up to len bytes from a raw memory buffer in a single send call.
Definition Socket.cpp:1033
std::size_t readIntoExact(void *buffer, const std::size_t len) const
Reads exactly len bytes into the given buffer (looped recv).
Definition Socket.hpp:872
Socket()=delete
Default constructor (deleted) for Socket class.
std::size_t readIntoAvailable(void *buffer, std::size_t bufferSize) const
Reads all currently available bytes into the provided buffer without blocking.
Definition Socket.cpp:814
std::size_t readInto(void *buffer, const std::size_t len) const
Reads available data from the socket into the provided buffer.
Definition Socket.hpp:819
std::string readPrefixed(const std::size_t maxPayloadLen)
Reads a length-prefixed message with an upper bound check.
Definition Socket.hpp:1074
int getSendBufferSize() const
Get the socket's send buffer size (SO_SNDBUF).
Definition Socket.cpp:331
Socket(Socket &&rhs) noexcept
Move constructor that transfers ownership of socket resources.
Definition Socket.hpp:257
size_t writeAll(std::string_view message) const
Writes the entire contents of a message to the socket, handling partial writes.
Definition Socket.cpp:301
std::size_t readvAll(std::span< BufferView > buffers) const
Reads exactly the full contents of all provided buffers.
Definition Socket.cpp:1234
std::size_t writev(std::span< const std::string_view > buffers) const
Writes multiple buffers in a single system call using scatter/gather I/O.
Definition Socket.cpp:916
bool isValid() const noexcept
Check if the socket is valid and open for communication.
Definition Socket.hpp:2387
std::size_t readvAllWithTotalTimeout(std::span< BufferView > buffers, int timeoutMillis) const
Reads exactly the full contents of all buffers within a timeout.
Definition Socket.cpp:1279
Socket(const Socket &rhs)=delete
Copy constructor (deleted) for Socket class.
void cleanupAndThrow(int errorCode)
Cleans up client socket resources and throws a SocketException.
Definition Socket.cpp:66
uint16_t toNetwork(const uint16_t val)
Converts a 16-bit unsigned integer from host to network byte order.
Definition common.hpp:444
uint16_t fromNetwork(const uint16_t val)
Converts a 16-bit unsigned integer from network to host byte order.
Definition common.hpp:460
A C++ socket library providing Java-style networking interfaces.
Definition BufferView.hpp:13
ShutdownMode
Enum for socket shutdown modes.
Definition common.hpp:292
int CloseSocket(SOCKET fd)
Definition common.hpp:208
std::string SocketErrorMessage(int error, bool gaiStrerror=false)
Returns a human-readable error message for a socket error code.
Definition common.cpp:5
constexpr SOCKET INVALID_SOCKET
Definition common.hpp:220
int GetSocketError()
Definition common.hpp:202
int SOCKET
Definition common.hpp:219
constexpr SOCKET SOCKET_ERROR
Definition common.hpp:221