-
Notifications
You must be signed in to change notification settings - Fork 0
/
netlibpp.cpp
executable file
·197 lines (179 loc) · 5.35 KB
/
netlibpp.cpp
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
///
/// Created by Anonymous275 on 1/2/22
/// Copyright (c) 2021-present Anonymous275 read the LICENSE file for more info.
///
#include "netlibpp.h"
#ifdef NETC_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#define NETC_RET_TYPE int
#define NETC_LEN_TYPE int
#else
#include <arpa/inet.h>
#include <cerrno>
#include <sys/socket.h>
#include <unistd.h>
#include <cstring>
#include <utility>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define SD_BOTH SHUT_RDWR
#define NETC_RET_TYPE ssize_t
#define NETC_LEN_TYPE uint32_t
#endif
namespace netlibpp {
sockaddr_in netc_sockaddr{};
Client::Client(const protocol& Protocol) noexcept :
Proto(Protocol) {
init();
}
Client::Client(errorFunc ErrorHandler, const protocol& Protocol) noexcept :
ErrFn(std::move(ErrorHandler)), Proto(Protocol) {
init();
}
inline void Client::handleError(bool netc) {
if(!netc && Err == 0) {
#ifdef NETC_WINDOWS
Err = WSAGetLastError();
#else
Err = errno;
#endif
}
if(ErrFn) {
ErrFn(get_error());
Err = 0;
}
}
void Client::init() {
#ifdef NETC_WINDOWS
WSADATA wsaData;
int Res = WSAStartup(MAKEWORD(2,2), &wsaData);
if (Res != 0) {
Err = Res;
handleError(false);
}
#endif
switch (Proto) {
case TCP:
SOCK = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
break;
case UDP:
SOCK = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
break;
}
if(SOCK == INVALID_SOCKET) {
handleError(false);
}
}
std::string Client::get_error() {
std::string Ret(256, 0);
if(!ErrBuf.empty()){
Ret = ErrBuf;
ErrBuf = "";
return Ret;
}
#ifdef NETC_WINDOWS
auto Res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
Err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
&Ret[0],
DWORD(Ret.size()),
nullptr);
if(Res != 0)Ret.resize(Res);
#else
Ret = std::strerror(Err);
#endif
return Ret;
}
inline void Client::killSocket(NETC_SOCKET Dead) {
if(Dead == INVALID_SOCKET)return;
shutdown(Dead, SD_BOTH);
#ifdef NETC_WINDOWS
if(closesocket(Dead) != 0 && WSAGetLastError() != 10038) {
handleError();
}
#else
if(close(Dead) != 0 && errno != EBADF){
handleError();
}
#endif
Connected = false;
}
void Client::set_target(const char* Address, int Port) {
netc_sockaddr.sin_family = AF_INET;
netc_sockaddr.sin_port = htons(Port);
netc_sockaddr.sin_addr.s_addr = inet_addr(Address);
HasTarget = true;
}
void Client::connect() {
if(Connected) {
ErrBuf = "Already connected to a server";
handleError(true);
return;
} else if(Proto != TCP) {
ErrBuf = "Cannot connect! Protocol is not TCP";
handleError(true);
return;
} else if(!HasTarget) {
ErrBuf = "Cannot connect! Please call the set_target method first";
handleError(true);
return;
}
int Res = ::connect(SOCK, (sockaddr*)&netc_sockaddr, sizeof(netc_sockaddr));
if(Res != 0){
handleError();
killSocket(SOCK);
return;
}
Connected = true;
}
size_t Client::send(const std::string& msg, flags flag) {
if(flag == NETC_ENFORCE_LENGTH && Proto != TCP)flag = NONE;
NETC_LEN_TYPE len = sizeof(netc_sockaddr);
NETC_RET_TYPE res;
size_t total = 0;
auto final_flag = flag == NETC_ENFORCE_LENGTH ? 0 : flag;
do {
res = ::sendto(SOCK, &msg[total], int(msg.size() - total), final_flag, (sockaddr*)&netc_sockaddr, len);
total += res;
}while(flag == NETC_ENFORCE_LENGTH && res != SOCKET_ERROR && total < msg.size());
if (res == SOCKET_ERROR) {
handleError();
killSocket(SOCK);
return 0;
}
return total;
}
messageType Client::receive(size_t length, flags flag) {
if(flag == NETC_ENFORCE_LENGTH && Proto != TCP)flag = NONE;
NETC_LEN_TYPE len = sizeof(netc_sockaddr);
NETC_RET_TYPE res;
size_t total = 0;
messageType buffer(length + 1, 0);
auto final_flag = flag == NETC_ENFORCE_LENGTH ? MSG_WAITALL : flag;
do {
res = ::recvfrom(SOCK, &buffer[total], int(length - total), final_flag, (sockaddr*)&netc_sockaddr, &len);
total += res;
} while(flag == NETC_ENFORCE_LENGTH && res > 0 && total < length);
if (res == SOCKET_ERROR) {
handleError();
killSocket(SOCK);
return {};
} else if(res == 0) {
Connected = false;
killSocket(SOCK);
}
buffer.resize(total);
return buffer;
}
Client::~Client() {
Connected = false;
killSocket(SOCK);
#ifdef NETC_WINDOWS
WSACleanup();
#endif
}
}