mirror of https://github.com/libAthena/athena.git
Implement base Socket class
Fix derp in IPAddress::resolve
This commit is contained in:
parent
9e7733eb02
commit
7c4d0bb6fd
|
@ -154,10 +154,12 @@ add_library(AthenaZelda EXCLUDE_FROM_ALL
|
|||
)
|
||||
|
||||
add_library(AthenaNet
|
||||
src/sockwrap.c
|
||||
src/Athena/Socket.cpp
|
||||
src/Athena/OAuth.cpp
|
||||
src/Athena/IPAddress.cpp
|
||||
|
||||
include/sockwrap.h
|
||||
include/Athena/Socket.hpp
|
||||
include/Athena/OAuth.hpp
|
||||
include/Athena/IPAddress.hpp)
|
||||
|
|
|
@ -1,15 +1,43 @@
|
|||
#ifndef SOCKET_HPP
|
||||
#define SOCKET_HPP
|
||||
|
||||
#include "Athena/Global.hpp"
|
||||
#include "sockwrap.h"
|
||||
|
||||
namespace Athena
|
||||
{
|
||||
namespace net
|
||||
{
|
||||
|
||||
class Socket
|
||||
{
|
||||
// Disable copying
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
TCP,
|
||||
UDP
|
||||
};
|
||||
|
||||
explicit Socket(Type type = TCP);
|
||||
|
||||
virtual ~Socket() { close() ; }
|
||||
|
||||
void setBlocking(bool blocking);
|
||||
bool isBlocking() const { return m_isBlocking; }
|
||||
protected:
|
||||
sockhandle_t handle() { return m_handle; }
|
||||
void create();
|
||||
void close();
|
||||
private:
|
||||
// Disable copying
|
||||
Socket(const Socket&)=delete;
|
||||
Socket& operator=(const Socket&)=delete;
|
||||
Type m_type;
|
||||
sockhandle_t m_handle;
|
||||
bool m_isBlocking;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef SOCKWRAP_H
|
||||
#define SOCKWRAP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32_WINDOWS
|
||||
#undef _WIN32_WINDOWS
|
||||
#endif
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINDOWS 0x0501
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <basetsd>
|
||||
|
||||
typedef UINT_PTR sockhandle_t;
|
||||
typedef int addrlen_t;
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef int32_t sockhandle_t;
|
||||
typedef socklen_t addrlen_t;
|
||||
#endif
|
||||
|
||||
#define ANY_PORT 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// TODO: More granular errors
|
||||
typedef enum
|
||||
{
|
||||
SS_Done,
|
||||
SS_NotReady,
|
||||
SS_Partial,
|
||||
SS_Disconnected,
|
||||
SS_Error
|
||||
} sockstatus_t;
|
||||
|
||||
struct sockaddr_in sock_create_address(uint32_t address, uint16_t port);
|
||||
void sock_close_socket(sockhandle_t sock);
|
||||
void sock_set_blocking(sockhandle_t sock, bool block);
|
||||
sockstatus_t sock_error_status();
|
||||
sockhandle_t sock_invalid_socket();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,25 +1,5 @@
|
|||
#include "Athena/IPAddress.hpp"
|
||||
|
||||
#ifdef __unix__
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(_WIN32)
|
||||
#ifdef _WIN32_WINDOWS
|
||||
#undef _WIN32_WINDOWS
|
||||
#endif
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINDOWS 0x0501
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
#include "sockwrap.h" // To resolve local IP
|
||||
|
||||
namespace Athena
|
||||
{
|
||||
|
@ -55,6 +35,35 @@ const std::string IPAddress::toString() const
|
|||
return inet_ntoa(address);
|
||||
}
|
||||
|
||||
const atUint32 IPAddress::toInt() const
|
||||
{
|
||||
return ntohl(m_address);
|
||||
}
|
||||
|
||||
IPAddress IPAddress::localAddress()
|
||||
{
|
||||
sockhandle_t sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == sock_invalid_socket())
|
||||
return IPAddress();
|
||||
|
||||
struct sockaddr_in address = sock_create_address(ntohl(INADDR_LOOPBACK), 9);
|
||||
if (connect(sock, reinterpret_cast<sockaddr*>(&address), sizeof(struct sockaddr_in)) == -1)
|
||||
{
|
||||
sock_close_socket(sock);
|
||||
return IPAddress();
|
||||
}
|
||||
|
||||
addrlen_t size = sizeof(address);
|
||||
if (getsockname(sock, reinterpret_cast<sockaddr*>(&address), &size) == -1)
|
||||
{
|
||||
sock_close_socket(sock);
|
||||
return IPAddress();
|
||||
}
|
||||
|
||||
sock_close_socket(sock);
|
||||
return IPAddress(ntohl(address.sin_addr.s_addr));
|
||||
}
|
||||
|
||||
void IPAddress::resolve(const std::string& address)
|
||||
{
|
||||
if (address == "0.0.0.0")
|
||||
|
@ -72,10 +81,11 @@ void IPAddress::resolve(const std::string& address)
|
|||
atUint32 ip = inet_addr(address.c_str());
|
||||
if (ip == INADDR_NONE)
|
||||
{
|
||||
addrinfo hints = {0};
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(addrinfo));
|
||||
hints.ai_family = AF_INET;
|
||||
addrinfo* result = nullptr;
|
||||
if (getaddrinfo(address.c_str(), NULL, &hints, &result))
|
||||
if (getaddrinfo(address.c_str(), nullptr, &hints, &result) == 0)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
|
|
|
@ -1 +1,53 @@
|
|||
#include "Athena/Socket.hpp"
|
||||
|
||||
namespace Athena
|
||||
{
|
||||
namespace net
|
||||
{
|
||||
|
||||
Socket::Socket(Socket::Type type)
|
||||
: m_type(type),
|
||||
m_handle(sock_invalid_socket()),
|
||||
m_isBlocking(true)
|
||||
{}
|
||||
|
||||
void Socket::create()
|
||||
{
|
||||
if (m_handle == sock_invalid_socket())
|
||||
{
|
||||
m_handle = socket(PF_INET, m_type == TCP ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||
setBlocking(m_isBlocking);
|
||||
|
||||
int yes = 1;
|
||||
if (m_type == TCP)
|
||||
{
|
||||
// Disable Nagle algorithm
|
||||
if (setsockopt(m_handle, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(int)) == -1)
|
||||
atWarning("Failed to set socket option \"TCP_NODELAY\", TCP packets will be buffered");
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (setsockopt(m_handle, SOL_SOCKET, SO_NOSIGPIPE, &yes, sizeof(int)) == -1)
|
||||
atWarning("Failed to set socket option \"SO_NOSIGPIPE\"");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (setsockopt(m_handle, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(int)) == -1)
|
||||
atWarning("Failed to enable broadcast on UDP socket");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Socket::close()
|
||||
{
|
||||
sock_close_socket(m_handle);
|
||||
m_handle = sock_invalid_socket();
|
||||
}
|
||||
|
||||
void Socket::setBlocking(bool blocking)
|
||||
{
|
||||
sock_set_blocking(m_handle, blocking);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
#include "sockwrap.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
struct sockaddr_in sock_create_address(uint32_t address, uint16_t port)
|
||||
{
|
||||
struct sockaddr_in addr = {0};
|
||||
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;
|
||||
}
|
||||
|
||||
void sock_close_socket(sockhandle_t sock)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
closesocket(sock);
|
||||
#else
|
||||
close(sock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sock_set_blocking(sockhandle_t sock, bool block)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
u_long blocking = block ? 0 : 1;
|
||||
ioctlsocket(sock, FIONBIO, &blocking);
|
||||
#else
|
||||
int status = fcntl(sock, F_GETFL);
|
||||
if (block)
|
||||
status &= ~O_NONBLOCK;
|
||||
else
|
||||
status |= O_NONBLOCK;
|
||||
|
||||
fcntl(sock, F_SETFL, status);
|
||||
#endif
|
||||
}
|
||||
|
||||
sockstatus_t sock_error_status()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
switch(WSAGetLastError())
|
||||
{
|
||||
case WSAEWOULDBLOCK:
|
||||
case WSAEALREADY:
|
||||
return SS_NotReady;
|
||||
case WSAECONNABORTED:
|
||||
case WSAECONNRESET:
|
||||
case WSATIMEDOUT:
|
||||
case WSAENETRESET:
|
||||
case WSAENOTCONN:
|
||||
return SS_Disconnected;
|
||||
case WSAEISCONN:
|
||||
return SS_Done;
|
||||
default:
|
||||
return SS_Error;
|
||||
}
|
||||
#else
|
||||
if (errno == EAGAIN || errno == EINPROGRESS)
|
||||
return SS_NotReady;
|
||||
|
||||
switch(errno)
|
||||
{
|
||||
case EWOULDBLOCK: return SS_NotReady;
|
||||
case ECONNABORTED:
|
||||
case ECONNRESET:
|
||||
case ETIMEDOUT:
|
||||
case ENETRESET:
|
||||
case ENOTCONN:
|
||||
case EPIPE:
|
||||
return SS_Disconnected;
|
||||
default:
|
||||
return SS_Error;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sockhandle_t sock_invalid_socket()
|
||||
{
|
||||
#if _WIN32
|
||||
return INVALID_SOCKET;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
Loading…
Reference in New Issue