Skip to content
This repository was archived by the owner on Apr 10, 2021. It is now read-only.

Commit 9b6ede3

Browse files
sockets
1 parent e6161aa commit 9b6ede3

File tree

7 files changed

+281
-40
lines changed

7 files changed

+281
-40
lines changed

byond-extools/src/core/byond_structures.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,21 @@ List::List(Value v)
143143
list = GetListPointerById(id);
144144
}
145145

146+
Container::Container(char type, int id) : type(type), id(id)
147+
{
148+
IncRefCount(type, id);
149+
}
150+
151+
Container::Container(Value val) : type(val.type), id(val.value)
152+
{
153+
IncRefCount(type, id);
154+
}
155+
156+
Container::~Container()
157+
{
158+
DecRefCount(type, id);
159+
}
160+
146161
unsigned int Container::length()
147162
{
148163
return Length(type, id);

byond-extools/src/core/byond_structures.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,9 @@ struct ContainerProxy
175175
struct Container //All kinds of lists, including magical snowflake lists like contents
176176
{
177177

178-
Container(char type, int id) : type(type), id(id) {}
179-
Container(Value val) : type(val.type), id(val.value) {}
178+
Container(char type, int id);
179+
Container(Value val);
180+
~Container();
180181
char type;
181182
int id;
182183

byond-extools/src/core/socket/socket.cpp

Lines changed: 76 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -58,27 +58,21 @@ bool Socket::create(int family, int socktype, int protocol)
5858
return raw_socket != INVALID_SOCKET;
5959
}
6060

61-
// Listening.
62-
bool TcpListener::listen(const char* port, const char* iface)
61+
bool connect_socket(Socket& socket, const char* port, const char* remote)
6362
{
63+
6464
struct addrinfo* result = NULL;
6565
struct addrinfo hints;
6666
int iResult;
6767

68-
// Initialize Winsock
69-
if (!InitOnce())
70-
{
71-
return false;
72-
}
73-
7468
ZeroMemory(&hints, sizeof(hints));
7569
hints.ai_family = AF_INET;
7670
hints.ai_socktype = SOCK_STREAM;
7771
hints.ai_protocol = IPPROTO_TCP;
7872
hints.ai_flags = AI_PASSIVE;
7973

8074
// Resolve the server address and port
81-
iResult = getaddrinfo(iface, port, &hints, &result);
75+
iResult = getaddrinfo(remote, port, &hints, &result);
8276
if (iResult != 0)
8377
{
8478
Core::Alert("getaddrinfo failed with error: " + std::to_string(iResult));
@@ -93,40 +87,21 @@ bool TcpListener::listen(const char* port, const char* iface)
9387
return false;
9488
}
9589

96-
// Set SO_REUSEADDR so if the process is killed, the port becomes reusable
97-
// immediately rather than after a 60-second delay.
98-
int opt = 1;
99-
setsockopt(socket.raw(), SOL_SOCKET, SO_REUSEADDR, (const char*) &opt, sizeof(int));
100-
10190
// Setup the TCP listening socket
102-
iResult = bind(socket.raw(), result->ai_addr, (int)result->ai_addrlen);
91+
iResult = ::connect(socket.raw(), result->ai_addr, (int)result->ai_addrlen);
10392
if (iResult == SOCKET_ERROR)
10493
{
105-
Core::Alert("bind failed with error: " + std::to_string(WSAGetLastError()));
94+
Core::Alert("connect failed with error: " + std::to_string(WSAGetLastError()));
10695
freeaddrinfo(result);
10796
socket.close();
10897
return false;
10998
}
11099

111-
freeaddrinfo(result);
112-
113-
iResult = ::listen(socket.raw(), SOMAXCONN);
114-
if (iResult == SOCKET_ERROR)
115-
{
116-
Core::Alert("listen failed with error: " + std::to_string(WSAGetLastError()));
117-
socket.close();
118-
return false;
119-
}
120-
121100
return true;
122101
}
123102

124-
JsonStream TcpListener::accept()
125-
{
126-
return JsonStream(Socket(::accept(socket.raw(), NULL, NULL)));
127-
}
128-
129-
bool JsonStream::connect(const char* port, const char* remote)
103+
// Listening.
104+
bool JsonListener::listen(const char* port, const char* iface)
130105
{
131106
struct addrinfo* result = NULL;
132107
struct addrinfo hints;
@@ -145,7 +120,7 @@ bool JsonStream::connect(const char* port, const char* remote)
145120
hints.ai_flags = AI_PASSIVE;
146121

147122
// Resolve the server address and port
148-
iResult = getaddrinfo(remote, port, &hints, &result);
123+
iResult = getaddrinfo(iface, port, &hints, &result);
149124
if (iResult != 0)
150125
{
151126
Core::Alert("getaddrinfo failed with error: " + std::to_string(iResult));
@@ -160,19 +135,50 @@ bool JsonStream::connect(const char* port, const char* remote)
160135
return false;
161136
}
162137

138+
// Set SO_REUSEADDR so if the process is killed, the port becomes reusable
139+
// immediately rather than after a 60-second delay.
140+
int opt = 1;
141+
setsockopt(socket.raw(), SOL_SOCKET, SO_REUSEADDR, (const char*) &opt, sizeof(int));
142+
163143
// Setup the TCP listening socket
164-
iResult = ::connect(socket.raw(), result->ai_addr, (int)result->ai_addrlen);
144+
iResult = bind(socket.raw(), result->ai_addr, (int)result->ai_addrlen);
165145
if (iResult == SOCKET_ERROR)
166146
{
167-
Core::Alert("connect failed with error: " + std::to_string(WSAGetLastError()));
147+
Core::Alert("bind failed with error: " + std::to_string(WSAGetLastError()));
168148
freeaddrinfo(result);
169149
socket.close();
170150
return false;
171151
}
172152

153+
freeaddrinfo(result);
154+
155+
iResult = ::listen(socket.raw(), SOMAXCONN);
156+
if (iResult == SOCKET_ERROR)
157+
{
158+
Core::Alert("listen failed with error: " + std::to_string(WSAGetLastError()));
159+
socket.close();
160+
return false;
161+
}
162+
173163
return true;
174164
}
175165

166+
JsonStream JsonListener::accept()
167+
{
168+
return JsonStream(Socket(::accept(socket.raw(), NULL, NULL)));
169+
}
170+
171+
bool JsonStream::connect(const char* port, const char* remote)
172+
{
173+
// Initialize Winsock
174+
if (!InitOnce())
175+
{
176+
return false;
177+
}
178+
179+
return connect_socket(socket, port, remote);
180+
}
181+
176182
bool JsonStream::send(const char* type, nlohmann::json content)
177183
{
178184
nlohmann::json j = {
@@ -218,3 +224,38 @@ nlohmann::json JsonStream::recv_message()
218224
recv_buffer.append(data.begin(), data.begin() + received_bytes);
219225
}
220226
}
227+
228+
bool TcpStream::connect(const char* port, const char* remote)
229+
{
230+
if (!InitOnce())
231+
{
232+
return false;
233+
}
234+
235+
return connect_socket(socket, port, remote);
236+
}
237+
238+
std::string TcpStream::recv()
239+
{
240+
std::vector<char> data(1024);
241+
int received_bytes = ::recv(socket.raw(), data.data(), data.size(), 0);
242+
if (received_bytes <= 0)
243+
{
244+
return "";
245+
}
246+
return std::string(data.begin(), data.begin() + received_bytes);
247+
}
248+
249+
bool TcpStream::send(std::string data)
250+
{
251+
while (!data.empty())
252+
{
253+
int sent_bytes = ::send(socket.raw(), data.c_str(), data.size(), 0);
254+
if (sent_bytes == SOCKET_ERROR)
255+
{
256+
return false;
257+
}
258+
data.erase(data.begin(), data.begin() + sent_bytes);
259+
}
260+
return true;
261+
}

byond-extools/src/core/socket/socket.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,22 @@ class JsonStream
4949
void close() { socket.close(); }
5050
};
5151

52-
class TcpListener
52+
class JsonListener
5353
{
5454
Socket socket;
5555
public:
56-
TcpListener() {}
56+
JsonListener() {}
5757
bool listen(const char* port = DBG_DEFAULT_PORT, const char* iface = "127.0.0.1");
5858
JsonStream accept();
5959
void close() { socket.close(); }
6060
};
61+
62+
class TcpStream
63+
{
64+
Socket socket;
65+
public:
66+
bool connect(const char* port, const char* remote); //augh, why port first?! damn it spaceman
67+
bool send(std::string data);
68+
std::string recv();
69+
void close() { socket.close(); }
70+
};
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#include "datum_socket.h"
2+
#include "../core/core.h"
3+
#include "../core/proc_management.h"
4+
5+
std::unordered_map<unsigned int, std::unique_ptr<DatumSocket>> sockets;
6+
unsigned int recv_sleep_opcode = -1;
7+
8+
DatumSocket::DatumSocket()
9+
{
10+
}
11+
12+
DatumSocket::DatumSocket(const DatumSocket& other)
13+
{
14+
}
15+
16+
DatumSocket::~DatumSocket()
17+
{
18+
close();
19+
}
20+
21+
bool DatumSocket::connect(std::string addr, std::string port)
22+
{
23+
stream = TcpStream();
24+
bool connected = stream.connect(port.c_str(), addr.c_str());
25+
if (connected)
26+
{
27+
std::thread(&DatumSocket::recv_loop, this).detach();
28+
}
29+
return connected;
30+
}
31+
32+
bool DatumSocket::send(std::string data)
33+
{
34+
return stream.send(data);
35+
}
36+
37+
std::string DatumSocket::recv(int len)
38+
{
39+
std::lock_guard<std::mutex> lk(buffer_lock);
40+
size_t nom = min(len, buffer.size());
41+
std::string sub = buffer.substr(0, nom);
42+
buffer.erase(buffer.begin(), buffer.begin() + nom);
43+
return sub;
44+
}
45+
46+
void DatumSocket::close()
47+
{
48+
stream.close();
49+
open = false;
50+
}
51+
52+
void DatumSocket::recv_loop()
53+
{
54+
while (open)
55+
{
56+
std::string data = stream.recv();
57+
if (data.empty())
58+
{
59+
close();
60+
return;
61+
}
62+
buffer_lock.lock();
63+
buffer += data;
64+
buffer_lock.unlock();
65+
if (data_awaiter)
66+
{
67+
data_awaiter->time_to_resume = 0;
68+
data_awaiter = nullptr;
69+
}
70+
}
71+
}
72+
73+
trvh register_socket(unsigned int args_len, Value* args, Value src)
74+
{
75+
//Core::Alert("register");
76+
sockets[src.value] = std::make_unique<DatumSocket>();
77+
return Value::Null();
78+
}
79+
80+
trvh connect_socket(unsigned int args_len, Value* args, Value src)
81+
{
82+
//Core::Alert("connect");
83+
return sockets[src.value]->connect(args[0], std::to_string((int)args[1].valuef)) ? Value::True() : Value::False();
84+
}
85+
86+
trvh send_socket(unsigned int args_len, Value* args, Value src)
87+
{
88+
//Core::Alert("send");
89+
return sockets[src.value]->send(args[0]) ? Value::True() : Value::False();
90+
}
91+
92+
trvh check_socket(unsigned int args_len, Value* args, Value src)
93+
{
94+
//Core::Alert("check");
95+
return sockets[src.value]->has_data() ? Value::True() : Value::False();
96+
}
97+
98+
trvh retrieve_socket(unsigned int args_len, Value* args, Value src)
99+
{
100+
//Core::Alert("retrieve");
101+
return Value(sockets[src.value]->recv(1024));
102+
}
103+
104+
trvh deregister_socket(unsigned int args_len, Value* args, Value src)
105+
{
106+
if (sockets.find(src.value) == sockets.end())
107+
{
108+
return Value::Null();
109+
}
110+
sockets[src.value].reset();
111+
sockets.erase(src.value);
112+
return Value::Null();
113+
}
114+
115+
void recv_suspend(ExecutionContext* ctx)
116+
{
117+
ctx->current_opcode++;
118+
SuspendedProc* proc = Suspend(ctx, 0);
119+
proc->time_to_resume = 0x7FFFFF;
120+
StartTiming(proc);
121+
int datum_id = ctx->constants->src.value;
122+
sockets[datum_id]->set_awaiter(proc);
123+
ctx->current_opcode--;
124+
}
125+
126+
bool enable_sockets()
127+
{
128+
Core::get_proc("/datum/socket/proc/__register_socket").hook(register_socket);
129+
Core::get_proc("/datum/socket/proc/__check_has_data").hook(check_socket);
130+
Core::get_proc("/datum/socket/proc/__retrieve_data").hook(retrieve_socket);
131+
Core::get_proc("/datum/socket/proc/connect").hook(connect_socket);
132+
Core::get_proc("/datum/socket/proc/send").hook(send_socket);
133+
Core::get_proc("/datum/socket/proc/__deregister_socket").hook(deregister_socket);
134+
recv_sleep_opcode = Core::register_opcode("RECV_SLEEP", recv_suspend);
135+
Core::get_proc("/datum/socket/proc/__wait_for_data").set_bytecode(new std::vector<std::uint32_t>({ recv_sleep_opcode, 0, 0, 0 }));
136+
return true;
137+
}
138+
139+
extern "C" __declspec(dllexport) const char* init_sockets(int a, const char** b)
140+
{
141+
enable_sockets();
142+
return "ok";
143+
}

0 commit comments

Comments
 (0)