mirror of https://github.com/AxioDL/jbus.git
Isolate WinSock2 header to translation unit
This commit is contained in:
parent
3b94b2d400
commit
2098e8da29
|
@ -13,7 +13,7 @@ endif()
|
||||||
include_directories(include)
|
include_directories(include)
|
||||||
add_library(jbus
|
add_library(jbus
|
||||||
include/jbus/optional.hpp
|
include/jbus/optional.hpp
|
||||||
include/jbus/Socket.hpp
|
lib/Socket.cpp include/jbus/Socket.hpp
|
||||||
lib/Common.cpp include/jbus/Common.hpp
|
lib/Common.cpp include/jbus/Common.hpp
|
||||||
lib/Endpoint.cpp include/jbus/Endpoint.hpp
|
lib/Endpoint.cpp include/jbus/Endpoint.hpp
|
||||||
lib/Listener.cpp include/jbus/Listener.hpp)
|
lib/Listener.cpp include/jbus/Listener.hpp)
|
||||||
|
|
|
@ -1,100 +1,38 @@
|
||||||
#ifndef JBUS_SOCKET_HPP
|
#ifndef JBUS_SOCKET_HPP
|
||||||
#define JBUS_SOCKET_HPP
|
#define JBUS_SOCKET_HPP
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <cerrno>
|
|
||||||
#else
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <Ws2tcpip.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <BaseTsd.h>
|
||||||
|
typedef UINT_PTR SOCKET;
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Common.hpp"
|
#include "Common.hpp"
|
||||||
|
|
||||||
|
struct sockaddr_in;
|
||||||
|
|
||||||
namespace jbus::net
|
namespace jbus::net
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Define the low-level send/receive flags, which depend on the OS */
|
|
||||||
#ifdef __linux__
|
|
||||||
static const int _flags = MSG_NOSIGNAL;
|
|
||||||
#else
|
|
||||||
static const int _flags = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** IP address class derived from SFML */
|
/** IP address class derived from SFML */
|
||||||
class IPAddress
|
class IPAddress
|
||||||
{
|
{
|
||||||
uint32_t m_address = 0;
|
uint32_t m_address = 0;
|
||||||
bool m_valid = false;
|
bool m_valid = false;
|
||||||
|
|
||||||
void resolve(std::string_view address)
|
void resolve(const std::string& address);
|
||||||
{
|
|
||||||
m_address = 0;
|
|
||||||
m_valid = false;
|
|
||||||
|
|
||||||
if (address == "255.255.255.255")
|
|
||||||
{
|
|
||||||
/* The broadcast address needs to be handled explicitly,
|
|
||||||
* because it is also the value returned by inet_addr on error */
|
|
||||||
m_address = INADDR_BROADCAST;
|
|
||||||
m_valid = true;
|
|
||||||
}
|
|
||||||
else if (address == "0.0.0.0")
|
|
||||||
{
|
|
||||||
m_address = INADDR_ANY;
|
|
||||||
m_valid = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Try to convert the address as a byte representation ("xxx.xxx.xxx.xxx") */
|
|
||||||
struct in_addr addr;
|
|
||||||
if (inet_pton(AF_INET, address.data(), &addr) == 1)
|
|
||||||
{
|
|
||||||
m_address = addr.s_addr;
|
|
||||||
m_valid = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Not a valid address, try to convert it as a host name */
|
|
||||||
addrinfo hints;
|
|
||||||
memset(&hints, 0, sizeof(hints));
|
|
||||||
hints.ai_family = AF_INET;
|
|
||||||
addrinfo* result = NULL;
|
|
||||||
if (getaddrinfo(address.data(), NULL, &hints, &result) == 0)
|
|
||||||
{
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
addr = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr;
|
|
||||||
freeaddrinfo(result);
|
|
||||||
m_address = addr.s_addr;
|
|
||||||
m_valid = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IPAddress(std::string_view address)
|
IPAddress(const std::string& address)
|
||||||
{
|
{
|
||||||
resolve(address);
|
resolve(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t toInteger() const
|
uint32_t toInteger() const;
|
||||||
{
|
|
||||||
return ntohl(m_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
operator bool() const { return m_valid; }
|
operator bool() const { return m_valid; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,50 +47,8 @@ class Socket
|
||||||
SocketTp m_socket = -1;
|
SocketTp m_socket = -1;
|
||||||
bool m_isBlocking;
|
bool m_isBlocking;
|
||||||
|
|
||||||
static sockaddr_in createAddress(uint32_t address, unsigned short port)
|
bool openSocket();
|
||||||
{
|
void setRemoteSocket(int remSocket);
|
||||||
sockaddr_in addr;
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sin_addr.s_addr = htonl(address);
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = htons(port);
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
addr.sin_len = sizeof(addr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool openSocket()
|
|
||||||
{
|
|
||||||
if (isOpen())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
||||||
if (m_socket == -1)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "jbus: Can't allocate socket\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int one = 1;
|
|
||||||
setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&one), sizeof(one));
|
|
||||||
#ifdef __APPLE__
|
|
||||||
setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char*>(&one), sizeof(one));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
setBlocking(m_isBlocking);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRemoteSocket(int remSocket)
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
m_socket = remSocket;
|
|
||||||
setBlocking(m_isBlocking);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class EResult
|
enum class EResult
|
||||||
|
@ -163,17 +59,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static EResult LastWSAError()
|
static EResult LastWSAError();
|
||||||
{
|
|
||||||
switch (WSAGetLastError())
|
|
||||||
{
|
|
||||||
case WSAEWOULDBLOCK:
|
|
||||||
case WSAEALREADY:
|
|
||||||
return EResult::Busy;
|
|
||||||
default:
|
|
||||||
return EResult::Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Socket(bool blocking)
|
Socket(bool blocking)
|
||||||
|
@ -196,173 +82,17 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBlocking(bool blocking)
|
void setBlocking(bool blocking);
|
||||||
{
|
|
||||||
m_isBlocking = blocking;
|
|
||||||
#ifndef _WIN32
|
|
||||||
int status = fcntl(m_socket, F_GETFL);
|
|
||||||
if (m_isBlocking)
|
|
||||||
fcntl(m_socket, F_SETFL, status & ~O_NONBLOCK);
|
|
||||||
else
|
|
||||||
fcntl(m_socket, F_SETFL, status | O_NONBLOCK);
|
|
||||||
#else
|
|
||||||
u_long b = blocking ? 0 : 1;
|
|
||||||
ioctlsocket(m_socket, FIONBIO, &b);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isOpen() const { return m_socket != -1; }
|
bool isOpen() const { return m_socket != -1; }
|
||||||
bool openAndListen(const IPAddress& address, uint32_t port)
|
bool openAndListen(const IPAddress& address, uint32_t port);
|
||||||
{
|
EResult accept(Socket& remoteSocketOut, sockaddr_in& fromAddress);
|
||||||
if (!openSocket())
|
EResult accept(Socket& remoteSocketOut);
|
||||||
return false;
|
EResult accept(Socket& remoteSocketOut, std::string& fromHostname);
|
||||||
|
void close();
|
||||||
sockaddr_in addr = createAddress(address.toInteger(), port);
|
EResult send(const void* buf, size_t len, size_t& transferred);
|
||||||
if (bind(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
|
EResult send(const void* buf, size_t len);
|
||||||
{
|
EResult recv(void* buf, size_t len, size_t& transferred);
|
||||||
/* Not likely to happen, but... */
|
EResult recv(void* buf, size_t len);
|
||||||
fprintf(stderr, "jbus: Failed to bind listener socket to port %d\n", port);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (::listen(m_socket, 0) == -1)
|
|
||||||
{
|
|
||||||
/* Oops, socket is deaf */
|
|
||||||
fprintf(stderr, "jbus: Failed to listen to port %d\n", port);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
EResult accept(Socket& remoteSocketOut, sockaddr_in& fromAddress)
|
|
||||||
{
|
|
||||||
if (!isOpen())
|
|
||||||
return EResult::Error;
|
|
||||||
|
|
||||||
/* Accept a new connection */
|
|
||||||
socklen_t length = sizeof(sockaddr_in);
|
|
||||||
int remoteSocket = ::accept(m_socket, reinterpret_cast<sockaddr*>(&fromAddress), &length);
|
|
||||||
|
|
||||||
/* Check for errors */
|
|
||||||
if (remoteSocket == -1)
|
|
||||||
{
|
|
||||||
#ifndef _WIN32
|
|
||||||
EResult res = (errno == EAGAIN) ? EResult::Busy : EResult::Error;
|
|
||||||
if (res == EResult::Error)
|
|
||||||
fprintf(stderr, "jbus: Failed to accept incoming connection: %s\n", strerror(errno));
|
|
||||||
#else
|
|
||||||
EResult res = LastWSAError();
|
|
||||||
if (res == EResult::Error)
|
|
||||||
fprintf(stderr, "jbus: Failed to accept incoming connection\n");
|
|
||||||
#endif
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the new connected socket */
|
|
||||||
remoteSocketOut.setRemoteSocket(remoteSocket);
|
|
||||||
|
|
||||||
return EResult::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
EResult accept(Socket& remoteSocketOut)
|
|
||||||
{
|
|
||||||
sockaddr_in fromAddress;
|
|
||||||
return accept(remoteSocketOut, fromAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
EResult accept(Socket& remoteSocketOut, std::string& fromHostname)
|
|
||||||
{
|
|
||||||
sockaddr_in fromAddress;
|
|
||||||
socklen_t len = sizeof(fromAddress);
|
|
||||||
char name[NI_MAXHOST];
|
|
||||||
EResult res = accept(remoteSocketOut, fromAddress);
|
|
||||||
if (res == EResult::OK)
|
|
||||||
if (getnameinfo((sockaddr*)&fromAddress, len, name, NI_MAXHOST, nullptr, 0, 0) == 0)
|
|
||||||
fromHostname.assign(name);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close()
|
|
||||||
{
|
|
||||||
if (!isOpen())
|
|
||||||
return;
|
|
||||||
#ifndef _WIN32
|
|
||||||
::close(m_socket);
|
|
||||||
#else
|
|
||||||
closesocket(m_socket);
|
|
||||||
#endif
|
|
||||||
m_socket = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
EResult send(const void* buf, size_t len, size_t& transferred)
|
|
||||||
{
|
|
||||||
transferred = 0;
|
|
||||||
if (!isOpen())
|
|
||||||
return EResult::Error;
|
|
||||||
|
|
||||||
if (!buf || !len)
|
|
||||||
return EResult::Error;
|
|
||||||
|
|
||||||
/* Loop until every byte has been sent */
|
|
||||||
int result = 0;
|
|
||||||
for (size_t sent = 0; sent < len; sent += result)
|
|
||||||
{
|
|
||||||
/* Send a chunk of data */
|
|
||||||
result = ::send(m_socket, static_cast<const char*>(buf) + sent, len - sent, _flags);
|
|
||||||
|
|
||||||
/* Check for errors */
|
|
||||||
if (result < 0)
|
|
||||||
#ifndef _WIN32
|
|
||||||
return (errno == EAGAIN) ? EResult::Busy : EResult::Error;
|
|
||||||
#else
|
|
||||||
return LastWSAError();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
transferred = len;
|
|
||||||
return EResult::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
EResult send(const void* buf, size_t len)
|
|
||||||
{
|
|
||||||
size_t transferred;
|
|
||||||
return send(buf, len, transferred);
|
|
||||||
}
|
|
||||||
|
|
||||||
EResult recv(void* buf, size_t len, size_t& transferred)
|
|
||||||
{
|
|
||||||
transferred = 0;
|
|
||||||
if (!isOpen())
|
|
||||||
return EResult::Error;
|
|
||||||
|
|
||||||
if (!buf)
|
|
||||||
return EResult::Error;
|
|
||||||
|
|
||||||
if (!len)
|
|
||||||
return EResult::OK;
|
|
||||||
|
|
||||||
/* Receive a chunk of bytes */
|
|
||||||
int result = ::recv(m_socket, static_cast<char*>(buf), static_cast<int>(len), _flags);
|
|
||||||
|
|
||||||
if (result < 0)
|
|
||||||
#ifndef _WIN32
|
|
||||||
return (errno == EAGAIN) ? EResult::Busy : EResult::Error;
|
|
||||||
#else
|
|
||||||
return LastWSAError();
|
|
||||||
#endif
|
|
||||||
else if (result == 0)
|
|
||||||
return EResult::Error;
|
|
||||||
|
|
||||||
transferred = result;
|
|
||||||
return EResult::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
EResult recv(void* buf, size_t len)
|
|
||||||
{
|
|
||||||
size_t transferred;
|
|
||||||
return recv(buf, len, transferred);
|
|
||||||
}
|
|
||||||
|
|
||||||
operator bool() const { return isOpen(); }
|
operator bool() const { return isOpen(); }
|
||||||
|
|
||||||
|
@ -371,4 +101,4 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // JBUS_SOCKET_HPP
|
#endif // ATHENA_SOCKET_HPP
|
||||||
|
|
|
@ -0,0 +1,304 @@
|
||||||
|
#include "jbus/Socket.hpp"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cerrno>
|
||||||
|
#else
|
||||||
|
#include <WinSock2.h>
|
||||||
|
#include <Ws2tcpip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace jbus::net
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Define the low-level send/receive flags, which depend on the OS */
|
||||||
|
#ifdef __linux__
|
||||||
|
static const int _flags = MSG_NOSIGNAL;
|
||||||
|
#else
|
||||||
|
static const int _flags = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void IPAddress::resolve(const std::string& address)
|
||||||
|
{
|
||||||
|
m_address = 0;
|
||||||
|
m_valid = false;
|
||||||
|
|
||||||
|
if (address == "255.255.255.255")
|
||||||
|
{
|
||||||
|
/* The broadcast address needs to be handled explicitly,
|
||||||
|
* because it is also the value returned by inet_addr on error */
|
||||||
|
m_address = INADDR_BROADCAST;
|
||||||
|
m_valid = true;
|
||||||
|
}
|
||||||
|
else if (address == "0.0.0.0")
|
||||||
|
{
|
||||||
|
m_address = INADDR_ANY;
|
||||||
|
m_valid = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Try to convert the address as a byte representation ("xxx.xxx.xxx.xxx") */
|
||||||
|
struct in_addr addr;
|
||||||
|
if (inet_pton(AF_INET, address.c_str(), &addr) == 1)
|
||||||
|
{
|
||||||
|
m_address = addr.s_addr;
|
||||||
|
m_valid = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Not a valid address, try to convert it as a host name */
|
||||||
|
addrinfo hints;
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
addrinfo* result = NULL;
|
||||||
|
if (getaddrinfo(address.c_str(), NULL, &hints, &result) == 0)
|
||||||
|
{
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
addr = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr;
|
||||||
|
freeaddrinfo(result);
|
||||||
|
m_address = addr.s_addr;
|
||||||
|
m_valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t IPAddress::toInteger() const
|
||||||
|
{
|
||||||
|
return ntohl(m_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
static sockaddr_in createAddress(uint32_t address, unsigned short port)
|
||||||
|
{
|
||||||
|
sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_addr.s_addr = htonl(address);
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
addr.sin_len = sizeof(addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::openSocket()
|
||||||
|
{
|
||||||
|
if (isOpen())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (m_socket == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Can't allocate socket");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int one = 1;
|
||||||
|
setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&one), sizeof(one));
|
||||||
|
#ifdef __APPLE__
|
||||||
|
setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char*>(&one), sizeof(one));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setBlocking(m_isBlocking);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Socket::setRemoteSocket(int remSocket)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
m_socket = remSocket;
|
||||||
|
setBlocking(m_isBlocking);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
Socket::EResult Socket::LastWSAError()
|
||||||
|
{
|
||||||
|
switch (WSAGetLastError())
|
||||||
|
{
|
||||||
|
case WSAEWOULDBLOCK:
|
||||||
|
case WSAEALREADY:
|
||||||
|
return EResult::Busy;
|
||||||
|
default:
|
||||||
|
return EResult::Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Socket::setBlocking(bool blocking)
|
||||||
|
{
|
||||||
|
m_isBlocking = blocking;
|
||||||
|
#ifndef _WIN32
|
||||||
|
int status = fcntl(m_socket, F_GETFL);
|
||||||
|
if (m_isBlocking)
|
||||||
|
fcntl(m_socket, F_SETFL, status & ~O_NONBLOCK);
|
||||||
|
else
|
||||||
|
fcntl(m_socket, F_SETFL, status | O_NONBLOCK);
|
||||||
|
#else
|
||||||
|
u_long b = blocking ? 0 : 1;
|
||||||
|
ioctlsocket(m_socket, FIONBIO, &b);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Socket::openAndListen(const IPAddress& address, uint32_t port)
|
||||||
|
{
|
||||||
|
if (!openSocket())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sockaddr_in addr = createAddress(address.toInteger(), port);
|
||||||
|
if (bind(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
|
||||||
|
{
|
||||||
|
/* Not likely to happen, but... */
|
||||||
|
fprintf(stderr, "Failed to bind listener socket to port %d", port);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (::listen(m_socket, 0) == -1)
|
||||||
|
{
|
||||||
|
/* Oops, socket is deaf */
|
||||||
|
fprintf(stderr, "Failed to listen to port %d", port);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::EResult Socket::accept(Socket& remoteSocketOut, sockaddr_in& fromAddress)
|
||||||
|
{
|
||||||
|
if (!isOpen())
|
||||||
|
return EResult::Error;
|
||||||
|
|
||||||
|
/* Accept a new connection */
|
||||||
|
socklen_t length = sizeof(sockaddr_in);
|
||||||
|
int remoteSocket = ::accept(m_socket, reinterpret_cast<sockaddr*>(&fromAddress), &length);
|
||||||
|
|
||||||
|
/* Check for errors */
|
||||||
|
if (remoteSocket == -1)
|
||||||
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
EResult res = (errno == EAGAIN) ? EResult::Busy : EResult::Error;
|
||||||
|
if (res == EResult::Error)
|
||||||
|
fprintf(stderr, "Failed to accept incoming connection: %s", strerror(errno));
|
||||||
|
#else
|
||||||
|
EResult res = LastWSAError();
|
||||||
|
if (res == EResult::Error)
|
||||||
|
fprintf(stderr, "Failed to accept incoming connection");
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the new connected socket */
|
||||||
|
remoteSocketOut.setRemoteSocket(remoteSocket);
|
||||||
|
|
||||||
|
return EResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::EResult Socket::accept(Socket& remoteSocketOut)
|
||||||
|
{
|
||||||
|
sockaddr_in fromAddress;
|
||||||
|
return accept(remoteSocketOut, fromAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::EResult Socket::accept(Socket& remoteSocketOut, std::string& fromHostname)
|
||||||
|
{
|
||||||
|
sockaddr_in fromAddress;
|
||||||
|
socklen_t len = sizeof(fromAddress);
|
||||||
|
char name[NI_MAXHOST];
|
||||||
|
EResult res = accept(remoteSocketOut, fromAddress);
|
||||||
|
if (res == EResult::OK)
|
||||||
|
if (getnameinfo((sockaddr*)&fromAddress, len, name, NI_MAXHOST, nullptr, 0, 0) == 0)
|
||||||
|
fromHostname.assign(name);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Socket::close()
|
||||||
|
{
|
||||||
|
if (!isOpen())
|
||||||
|
return;
|
||||||
|
#ifndef _WIN32
|
||||||
|
::close(m_socket);
|
||||||
|
#else
|
||||||
|
closesocket(m_socket);
|
||||||
|
#endif
|
||||||
|
m_socket = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::EResult Socket::send(const void* buf, size_t len, size_t& transferred)
|
||||||
|
{
|
||||||
|
transferred = 0;
|
||||||
|
if (!isOpen())
|
||||||
|
return EResult::Error;
|
||||||
|
|
||||||
|
if (!buf || !len)
|
||||||
|
return EResult::Error;
|
||||||
|
|
||||||
|
/* Loop until every byte has been sent */
|
||||||
|
int result = 0;
|
||||||
|
for (size_t sent = 0; sent < len; sent += result)
|
||||||
|
{
|
||||||
|
/* Send a chunk of data */
|
||||||
|
result = ::send(m_socket, static_cast<const char*>(buf) + sent, len - sent, _flags);
|
||||||
|
|
||||||
|
/* Check for errors */
|
||||||
|
if (result < 0)
|
||||||
|
#ifndef _WIN32
|
||||||
|
return (errno == EAGAIN) ? EResult::Busy : EResult::Error;
|
||||||
|
#else
|
||||||
|
return LastWSAError();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
transferred = len;
|
||||||
|
return EResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::EResult Socket::send(const void* buf, size_t len)
|
||||||
|
{
|
||||||
|
size_t transferred;
|
||||||
|
return send(buf, len, transferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::EResult Socket::recv(void* buf, size_t len, size_t& transferred)
|
||||||
|
{
|
||||||
|
transferred = 0;
|
||||||
|
if (!isOpen())
|
||||||
|
return EResult::Error;
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return EResult::Error;
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
return EResult::OK;
|
||||||
|
|
||||||
|
/* Receive a chunk of bytes */
|
||||||
|
int result = ::recv(m_socket, static_cast<char*>(buf), static_cast<int>(len), _flags);
|
||||||
|
|
||||||
|
if (result < 0)
|
||||||
|
#ifndef _WIN32
|
||||||
|
return (errno == EAGAIN) ? EResult::Busy : EResult::Error;
|
||||||
|
#else
|
||||||
|
return LastWSAError();
|
||||||
|
#endif
|
||||||
|
else if (result == 0)
|
||||||
|
return EResult::Error;
|
||||||
|
|
||||||
|
transferred = result;
|
||||||
|
return EResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket::EResult Socket::recv(void* buf, size_t len)
|
||||||
|
{
|
||||||
|
size_t transferred;
|
||||||
|
return recv(buf, len, transferred);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue