forked from lpcvoid/cpp-net-lib
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsocket.hpp
More file actions
127 lines (111 loc) · 3.31 KB
/
Copy pathsocket.hpp
File metadata and controls
127 lines (111 loc) · 3.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#pragma once
#include <system_error>
#include <optional>
#ifdef _WIN32
//libs
#pragma comment(lib, "Mswsock.lib")
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "AdvApi32.lib")
//headers
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <Windows.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>
#include <stdint.h>
//defines
using socket_t = SOCKET;
using socklen_t = int32_t;
using ssize_t = signed long long int;
#else
//headers
#include <arpa/inet.h>
#include <chrono>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
//defines
using socket_t = int32_t;
//this is actually a nice one to have
#define INVALID_SOCKET (-1)
#endif
namespace netlib {
static std::error_condition socket_get_last_error(){
std::error_code ec;
#ifdef _WIN32
ec = std::error_code(::GetLastError(), std::system_category());
#else
ec = std::error_code(errno, std::system_category());
#endif
return ec.default_error_condition();
}
enum class AddressFamily {IPv4 = AF_INET, IPv6 = AF_INET6, unspecified = AF_UNSPEC};
enum class AddressProtocol {TCP = SOCK_STREAM, UDP = SOCK_DGRAM};
enum class OperationClass {read = 1, write = 2, both = 3};
class socket {
private:
std::optional<socket_t> _socket = std::nullopt;
public:
socket() = default;
static bool initialize_system() {
#ifdef _WIN32
static bool initialized = false;
if (!initialized) {
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
initialized = true;
}
#endif
return true;
}
bool is_valid() {
return _socket.has_value() && _socket.value() != INVALID_SOCKET;
}
[[nodiscard]] std::optional<socket_t> get_raw() const {
return _socket.value();
}
bool set_nonblocking(bool nonblocking = true) {
#ifdef _WIN32
u_long mode = static_cast<u_long>(nonblocking);
return ioctlsocket(_socket.value(), FIONBIO, &mode) == 0;
#else
return fcntl(_socket.value(), F_SETFL, fcntl(_socket.value(), F_GETFL, 0) | (nonblocking ? O_NONBLOCK : 0)) == 0;
#endif
}
bool set_reuseaddr(bool reuseaddr = true){
#ifdef _WIN32
int32_t val = static_cast<int32_t>(reuseaddr);
return setsockopt(_socket.value(), SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<char*>(&val), sizeof(val)) == 0;
#else
auto mode = static_cast<int32_t>(reuseaddr);
return setsockopt(_socket.value(), SOL_SOCKET, SO_REUSEADDR, &mode, sizeof(int32_t)) == 0;
#endif
}
std::error_condition create(int32_t domain, int32_t stype, int32_t protocol) {
initialize_system();
socket_t new_socket = ::socket(domain, stype, protocol);
if (new_socket == INVALID_SOCKET) {
return socket_get_last_error();
}
_socket = new_socket;
return {};
}
void set_raw(socket_t sock) {
_socket = sock;
}
void close() {
if (_socket) {
#ifdef _WIN32
closesocket(_socket.value());
#else
::close(_socket.value());
#endif
_socket.reset();
}
}
};
}