11 #define WIN32_LEAN_AND_MEAN
14 #pragma comment(lib, "Ws2_32.lib")
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
29 #include <sys/select.h>
31 #define INVALID_SOCKET -1
32 #define SOCKET_ERROR -1
48 SocketImpl() : hSocket(INVALID_SOCKET) {}
54 if (hSocket != INVALID_SOCKET) {
60 hSocket = INVALID_SOCKET;
67 return WSAGetLastError();
75 static bool bInitialized =
false;
76 static std::mutex mutexInit;
77 std::lock_guard<std::mutex> lock(mutexInit);
80 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
84 std::atexit([]() { WSACleanup(); });
94 return socket(af, type, proto);
96 return ::socket(af, type, proto);
101 std::memset(&addr, 0,
sizeof(addr));
102 addr.sin_family = AF_INET;
103 addr.sin_port = htons(
static_cast<u_short
>(port));
104 if (ip.
IsEmpty() || ip ==
"0.0.0.0") {
105 addr.sin_addr.s_addr = INADDR_ANY;
107 if (inet_pton(AF_INET, ip.
GetRawString(), &addr.sin_addr) != 1) {
114 : m_pImpl(new SocketImpl()) {
120 if (m_pImpl->hSocket == INVALID_SOCKET) {
126 : m_pImpl(new SocketImpl()) {
132 m_pImpl->hSocket =
reinterpret_cast<SOCKET
>(pNativeHandle);
134 m_pImpl->hSocket =
static_cast<int>(
reinterpret_cast<intptr_t
>(pNativeHandle));
143 if (
this != &other) m_pImpl = std::move(other.m_pImpl);
149 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET)
throw SocketException(-1,
String(
"Socket is closed."));
156 setsockopt(m_pImpl->hSocket, SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<const char*
>(&optval),
sizeof(optval));
158 ::setsockopt(m_pImpl->hSocket, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval));
162 if (bind(m_pImpl->hSocket,
reinterpret_cast<sockaddr*
>(&addr),
sizeof(addr)) == SOCKET_ERROR) {
169 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET) {
174 if (listen(m_pImpl->hSocket, backlog) == SOCKET_ERROR) {
181 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET) {
186 sockaddr_in clientAddr;
187 SockLen clientSize =
sizeof(clientAddr);
189 SOCKET clientSocket = accept(m_pImpl->hSocket,
reinterpret_cast<sockaddr*
>(&clientAddr), &clientSize);
191 int clientSocket = ::accept(m_pImpl->hSocket,
reinterpret_cast<sockaddr*
>(&clientAddr), &clientSize);
193 if (clientSocket == INVALID_SOCKET) {
202 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET)
throw SocketException(-1,
"Socket is closed.");
207 if (connect(m_pImpl->hSocket,
reinterpret_cast<sockaddr*
>(&addr),
sizeof(addr)) == SOCKET_ERROR) {
214 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET)
throw SocketException(-1,
"Socket is closed.");
217 int bytesSent = send(m_pImpl->hSocket, buffer + offset, size, 0);
224 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET)
throw SocketException(-1,
"Socket is closed.");
227 int bytesReceived = recv(m_pImpl->hSocket, buffer + offset, size, 0);
229 return bytesReceived;
234 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET)
throw SocketException(-1,
"Socket is closed.");
239 int bytesSent = sendto(m_pImpl->hSocket, buffer + offset, size, 0,
reinterpret_cast<sockaddr*
>(&addr),
sizeof(addr));
245 char ipBuf[INET_ADDRSTRLEN];
246 if (inet_ntop(AF_INET, &addr.sin_addr, ipBuf,
sizeof(ipBuf)) !=
nullptr) {
249 port = ntohs(addr.sin_port);
254 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET)
throw SocketException(-1,
"Socket is closed.");
258 SockLen addrSize =
sizeof(addr);
259 std::memset(&addr, 0,
sizeof(addr));
260 int bytesReceived = recvfrom(m_pImpl->hSocket, buffer + offset, size, 0,
reinterpret_cast<sockaddr*
>(&addr), &addrSize);
264 return bytesReceived;
269 if (m_pImpl) m_pImpl->Cleanup();
274 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET)
return;
278 shutdown(m_pImpl->hSocket, nativeHow);
284 FD_SET(hSocket, &fds);
285 timeval timeout{ microSeconds / 1000000, microSeconds % 1000000 };
290 return select(0, pRead, pWrite, pErr, &timeout);
292 return select(hSocket + 1, pRead, pWrite, pErr, &timeout);
297 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET)
return false;
302 sockaddr_in peerAddr;
303 SockLen peerLen =
sizeof(peerAddr);
304 return (getpeername(hSocket,
reinterpret_cast<sockaddr*
>(&peerAddr), &peerLen) != SOCKET_ERROR);
310 int result = recv(hSocket, &buf, 1, MSG_PEEK);
311 if (result == 0)
return false;
312 return (result != SOCKET_ERROR || WSAGetLastError() == WSAEWOULDBLOCK);
314 int result = ::recv(hSocket, &buf, 1, MSG_PEEK | MSG_DONTWAIT);
315 if (result == 0)
return false;
316 return (result != SOCKET_ERROR || (errno == EAGAIN || errno == EWOULDBLOCK));
321 if (!m_pImpl || m_pImpl->hSocket == INVALID_SOCKET || !
IsPeerConnected(m_pImpl->hSocket))
return false;
323 if (sel == SOCKET_ERROR)
return false;
324 if (sel == 0)
return true;
329 return m_pImpl ?
reinterpret_cast<void*
>(m_pImpl->hSocket) :
nullptr;
Defines the exception thrown when an invalid argument is provided to a method.
Implements the Berkeley sockets interface for network communications.
Exception thrown when a network socket error occurs per RFC 793 / RFC 768.
High-performance UTF-8 / UTF-16 string manipulation class mirroring .NET System.String.
ArgumentException(const String &sMessage)
Initializes a new instance of the ArgumentException class with a specified error message.
SocketException(int errorCode, const String &message)
Initializes a new instance of the SocketException class with the specified error code and message.
int Receive(char *buffer, int offset, int size)
Receives data from a bound Socket into a receive buffer.
bool Connected() const
Gets a value that indicates whether a Socket is connected to a remote host as of the last Send or Rec...
bool Poll(int microSeconds, SelectMode mode)
Determines the status of the Socket.
~Socket()
Destructor closing encapsulated socket handles.
SmartPointer< Socket > Accept()
Creates a new Socket for a newly created connection.
int SendTo(const char *buffer, int offset, int size, const String &ip, int port)
Sends data to the specified endpoint.
Socket & operator=(const Socket &)=delete
int Send(const char *buffer, int offset, int size)
Sends data to a connected Socket.
void Bind(const String &ip, int port)
Associates a Socket with a local endpoint.
void Shutdown(SocketShutdown how)
Disables sends and receives on a Socket.
void * GetNativeHandle() const
Retrieves the underlying native socket descriptor.
int ReceiveFrom(char *buffer, int offset, int size, String &ip, int &port)
Receives a datagram into the data buffer and stores the endpoint.
void Listen(int backlog)
Places a Socket in a listening state.
Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
Initializes a new instance of the Socket class using the specified address family,...
void Close()
Closes the Socket connection and releases all associated resources.
void Connect(const String &ip, int port)
Establishes a connection to a remote host.
A unified smart pointer that supports both unique and shared ownership semantics.
friend class SmartPointer
Represents text as a sequence of UTF-8 code units with culture-invariant operations.
String()
Initializes a new instance of the String class to an empty string.
const char * GetRawString() const
static SOCKET CreateNativeSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
static void InitSockAddrIn(const String &ip, int port, sockaddr_in &addr)
static int GetLastErrorCode()
static int SelectSingleSocket(SOCKET hSocket, int microSeconds, SelectMode mode)
SelectMode
Defines the polling modes for the Socket.Poll method.
static bool IsPeerConnected(SOCKET hSocket)
AddressFamily
Specifies the addressing scheme that an instance of the Socket class can use.
SocketShutdown
Defines constants that are used by the Socket.Shutdown method.
static void FormatSockAddrIp(const sockaddr_in &addr, String &ip, int &port)
ProtocolType
Specifies the protocols that the Socket class supports.
static void InitializeSockets()
static bool IsSocketActivePeek(SOCKET hSocket)
SocketType
Specifies the type of socket that an instance of the Socket class represents.