Refactored structure and added sockets
This commit is contained in:
parent
85ea7fb6ac
commit
379292ae34
6
Makefile
6
Makefile
@ -1,5 +1,7 @@
|
|||||||
MUSH2021: src/mush2021.cpp
|
STATIC_LIBRARIES=/usr/lib/x86_64-linux-gnu/libuv_a.a
|
||||||
gcc -o mush2021 src/mush2021.cpp -lstdc++
|
|
||||||
|
MUSH2021: src/classes.cpp src/classes.hpp src/socketserver.cpp src/socketserver.hpp src/mush2021.cpp
|
||||||
|
gcc -o mush2021 src/classes.cpp src/socketserver.cpp src/mush2021.cpp $(STATIC_LIBRARIES) -lstdc++ -lpthread -ldl
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f mush2021
|
rm -f mush2021
|
||||||
|
31
README.md
31
README.md
@ -12,6 +12,14 @@ Please note that at this state of development if you see this README with this t
|
|||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
### Dependancies
|
||||||
|
|
||||||
|
* UV
|
||||||
|
* pthreads
|
||||||
|
* MySQL client
|
||||||
|
|
||||||
|
### Compiling
|
||||||
|
|
||||||
The root folder of the project contains a Makefile, currently there are only 2 rules:
|
The root folder of the project contains a Makefile, currently there are only 2 rules:
|
||||||
|
|
||||||
* MUSH2021 - Build the server
|
* MUSH2021 - Build the server
|
||||||
@ -20,8 +28,29 @@ The root folder of the project contains a Makefile, currently there are only 2 r
|
|||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
#### Version: 0.0.1
|
#### Version: 0.0.1
|
||||||
This is the very first version!
|
This is the very first version! This version fleshes out the beginning skeleton of the project and the base core ideas that will be the foundation of MUSH2021.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
__ _____ _______ __ _____ ____ ___ ___
|
||||||
|
/ |/ / / / / ___// / / /__ \ / __ \__ \< /
|
||||||
|
/ /|_/ / / / /\__ \/ /_/ /__/ // / / /_/ // /
|
||||||
|
/ / / / /_/ /___/ / __ // __// /_/ / __// /
|
||||||
|
/_/ /_/\____//____/_/ /_//____/\____/____/_/
|
||||||
|
|
||||||
|
Copyright (C) 2021 MatCat
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
MUSH 2021 uses the GNU General Public License v3.0, please see the file LICENSE for complete text of the license.
|
MUSH 2021 uses the GNU General Public License v3.0, please see the file LICENSE for complete text of the license.
|
||||||
|
79
src/classes.cpp
Normal file
79
src/classes.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
__ _____ _______ __ _____ ____ ___ ___
|
||||||
|
/ |/ / / / / ___// / / /__ \ / __ \__ \< /
|
||||||
|
/ /|_/ / / / /\__ \/ /_/ /__/ // / / /_/ // /
|
||||||
|
/ / / / /_/ /___/ / __ // __// /_/ / __// /
|
||||||
|
/_/ /_/\____//____/_/ /_//____/\____/____/_/
|
||||||
|
|
||||||
|
Copyright (C) 2021 MatCat
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "classes.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
/*
|
||||||
|
________ ___ __________ ___________
|
||||||
|
/ ____/ / / | / ___/ ___// ____/ ___/
|
||||||
|
/ / / / / /| | \__ \\__ \/ __/ \__ \
|
||||||
|
/ /___/ /___/ ___ |___/ /__/ / /___ ___/ /
|
||||||
|
\____/_____/_/ |_/____/____/_____//____/
|
||||||
|
|
||||||
|
|
||||||
|
_________________________________________________________________________________________________
|
||||||
|
/ ↓ ↓ ↓ ↓ ↓ ↓ \
|
||||||
|
*/
|
||||||
|
|
||||||
|
void BaseObject::printName() {
|
||||||
|
printf("Name: %s (#%X)\n",Name.c_str(),ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseObject::SetVariable(string var, string val) {
|
||||||
|
for (auto i = Variables.begin() ; i != Variables.end(); i++) {
|
||||||
|
if (i->Name == var) {
|
||||||
|
i->Value = val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VariableVector v_v;
|
||||||
|
v_v.Name = var;
|
||||||
|
v_v.Value = val;
|
||||||
|
Variables.push_back(v_v);
|
||||||
|
}
|
||||||
|
string BaseObject::getVariable(string var) {
|
||||||
|
for (auto i = Variables.begin() ; i != Variables.end(); i++) {
|
||||||
|
if (i->Name == var) return i->Value;
|
||||||
|
}
|
||||||
|
return (string) NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserObject::printUserInfo() {
|
||||||
|
this->printName();
|
||||||
|
printf("Inside of: %s (#%X)\nPassword: %s\n",Container->Name.c_str(),Container->ID,Password.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
\________↑_______________↑_______________↑_______________↑_______________↑_______________↑________/
|
||||||
|
END OF SECTION: CLASSES /
|
||||||
|
________________________________________________________________________________________________/
|
||||||
|
*/
|
56
src/classes.hpp
Normal file
56
src/classes.hpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
__ _____ _______ __ _____ ____ ___ ___
|
||||||
|
/ |/ / / / / ___// / / /__ \ / __ \__ \< /
|
||||||
|
/ /|_/ / / / /\__ \/ /_/ /__/ // / / /_/ // /
|
||||||
|
/ / / / /_/ /___/ / __ // __// /_/ / __// /
|
||||||
|
/_/ /_/\____//____/_/ /_//____/\____/____/_/
|
||||||
|
|
||||||
|
Copyright (C) 2021 MatCat
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class VariableVector {
|
||||||
|
public:
|
||||||
|
std::string Name;
|
||||||
|
std::string Value; // TODO: Template this for different types
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaseObject {
|
||||||
|
public:
|
||||||
|
uint64_t ID;
|
||||||
|
std::string Name;
|
||||||
|
BaseObject *Container;
|
||||||
|
std::vector<VariableVector> Variables;
|
||||||
|
|
||||||
|
void printName();
|
||||||
|
void SetVariable(std::string var, std::string val);
|
||||||
|
std::string getVariable(std::string var);
|
||||||
|
};
|
||||||
|
|
||||||
|
class UserObject: public BaseObject {
|
||||||
|
public:
|
||||||
|
std::string Password;
|
||||||
|
void printUserInfo();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectVector {
|
||||||
|
public:
|
||||||
|
uint64_t ID;
|
||||||
|
BaseObject *Object;
|
||||||
|
};
|
@ -1,4 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
|
__ _____ _______ __ _____ ____ ___ ___
|
||||||
|
/ |/ / / / / ___// / / /__ \ / __ \__ \< /
|
||||||
|
/ /|_/ / / / /\__ \/ /_/ /__/ // / / /_/ // /
|
||||||
|
/ / / / /_/ /___/ / __ // __// /_/ / __// /
|
||||||
|
/_/ /_/\____//____/_/ /_//____/\____/____/_/
|
||||||
|
|
||||||
Copyright (C) 2021 MatCat
|
Copyright (C) 2021 MatCat
|
||||||
|
|
||||||
@ -19,84 +24,16 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <uv.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "classes.hpp"
|
||||||
|
#include "socketserver.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
________ ___ __________ ___________
|
|
||||||
/ ____/ / / | / ___/ ___// ____/ ___/
|
|
||||||
/ / / / / /| | \__ \\__ \/ __/ \__ \
|
|
||||||
/ /___/ /___/ ___ |___/ /__/ / /___ ___/ /
|
|
||||||
\____/_____/_/ |_/____/____/_____//____/
|
|
||||||
|
|
||||||
TODO: Move this entire section to their own files
|
|
||||||
_________________________________________________________________________________________________
|
|
||||||
/ ↓ ↓ ↓ ↓ ↓ ↓ \
|
|
||||||
*/
|
|
||||||
|
|
||||||
class VariableVector {
|
|
||||||
public:
|
|
||||||
string Name;
|
|
||||||
string Value; // TODO: Template this for different types
|
|
||||||
};
|
|
||||||
|
|
||||||
class BaseObject {
|
|
||||||
public:
|
|
||||||
uint64_t ID;
|
|
||||||
string Name;
|
|
||||||
BaseObject *Container;
|
|
||||||
vector<VariableVector> Variables;
|
|
||||||
|
|
||||||
void printName() {
|
|
||||||
printf("Name: %s (#%X)\n",Name.c_str(),ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVariable(string var, string val) {
|
|
||||||
for (auto i = Variables.begin() ; i != Variables.end(); i++) {
|
|
||||||
if (i->Name == var) {
|
|
||||||
i->Value = val;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VariableVector v_v;
|
|
||||||
v_v.Name = var;
|
|
||||||
v_v.Value = val;
|
|
||||||
Variables.push_back(v_v);
|
|
||||||
}
|
|
||||||
string getVariable(string var) {
|
|
||||||
for (auto i = Variables.begin() ; i != Variables.end(); i++) {
|
|
||||||
if (i->Name == var) return i->Value;
|
|
||||||
}
|
|
||||||
return (string) NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class UserObject: public BaseObject {
|
|
||||||
public:
|
|
||||||
string Password;
|
|
||||||
void printUserInfo() {
|
|
||||||
this->printName();
|
|
||||||
printf("Inside of: %s (#%X)\nPassword: %s\n",Container->Name.c_str(),Container->ID,Password.c_str());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ObjectVector {
|
|
||||||
public:
|
|
||||||
uint64_t ID;
|
|
||||||
BaseObject *Object;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
\________↑_______________↑_______________↑_______________↑_______________↑_______________↑________/
|
|
||||||
END OF SECTION: CLASSES /
|
|
||||||
________________________________________________________________________________________________/
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint64_t AllocatedIndex;
|
uint64_t AllocatedIndex;
|
||||||
vector<ObjectVector> ObjectMap;
|
vector<ObjectVector> ObjectMap;
|
||||||
|
|
||||||
@ -156,5 +93,5 @@ int main() {
|
|||||||
if (TestObj2 != NULL) printf("Object #3 is: %s which is contained in %s, it is loaded with %s rounds\n",TestObj2->Name.c_str(),TestObj2->Container->Name.c_str(),TestObj2->getVariable("Loaded").c_str());
|
if (TestObj2 != NULL) printf("Object #3 is: %s which is contained in %s, it is loaded with %s rounds\n",TestObj2->Name.c_str(),TestObj2->Container->Name.c_str(),TestObj2->getVariable("Loaded").c_str());
|
||||||
|
|
||||||
printf("There are %u objects in existance\n",ObjectMap.size());
|
printf("There are %u objects in existance\n",ObjectMap.size());
|
||||||
return 0;
|
setupSocketServer();
|
||||||
}
|
}
|
143
src/socketserver.cpp
Normal file
143
src/socketserver.cpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
__ _____ _______ __ _____ ____ ___ ___
|
||||||
|
/ |/ / / / / ___// / / /__ \ / __ \__ \< /
|
||||||
|
/ /|_/ / / / /\__ \/ /_/ /__/ // / / /_/ // /
|
||||||
|
/ / / / /_/ /___/ / __ // __// /_/ / __// /
|
||||||
|
/_/ /_/\____//____/_/ /_//____/\____/____/_/
|
||||||
|
|
||||||
|
Copyright (C) 2021 MatCat
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <uv.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "socketserver.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
/*
|
||||||
|
__ ________ __ ___ __
|
||||||
|
/ / / _/ __ )/ / / / | / /
|
||||||
|
/ / / // __ / / / /| | / /
|
||||||
|
/ /____/ // /_/ / /_/ / | |/ /
|
||||||
|
/_____/___/_____/\____/ |___/
|
||||||
|
|
||||||
|
|
||||||
|
_________________________________________________________________________________________________
|
||||||
|
/ ↓ ↓ ↓ ↓ ↓ ↓ \
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
uv_loop_t *loop;
|
||||||
|
uv_tcp_t server;
|
||||||
|
|
||||||
|
void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
|
||||||
|
buf->base = (char*) malloc(suggested_size);
|
||||||
|
buf->len = suggested_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int setupSocketServer() {
|
||||||
|
loop = uv_default_loop();
|
||||||
|
uv_tcp_init(loop, &server);
|
||||||
|
struct sockaddr_in bind_addr;
|
||||||
|
uv_ip4_addr("0.0.0.0", 1701, &bind_addr);
|
||||||
|
uv_tcp_bind(&server, (const struct sockaddr*)&bind_addr, 0);
|
||||||
|
int r = uv_listen((uv_stream_t*) &server, 512, on_new_connection);
|
||||||
|
if (r) {
|
||||||
|
fprintf(stderr, "ERROR Could not bind to host and port!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return uv_run(loop, UV_RUN_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void client_write(uv_write_t *req, int status) {
|
||||||
|
if (status == -1) {
|
||||||
|
fprintf(stderr, "Write error!\n");
|
||||||
|
}
|
||||||
|
char *base = (char*) req->data;
|
||||||
|
free(base);
|
||||||
|
free(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_Message(uv_stream_t* client, char* msg) {
|
||||||
|
uv_buf_t outbuf = uv_buf_init(msg, strlen(msg));
|
||||||
|
uv_write_t *outreq = (uv_write_t *) malloc(sizeof(uv_write_t));
|
||||||
|
uv_write(outreq, (uv_stream_t *) client, &outbuf, 1, client_write);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void client_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
|
||||||
|
if (nread == -1) {
|
||||||
|
fprintf(stderr, "Read error!\n");
|
||||||
|
uv_close((uv_handle_t*)client, (uv_close_cb) free);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("Got %d bytes\n%s",nread,buf->base);
|
||||||
|
if (nread > 0) {
|
||||||
|
if (buf->base[0] == '@') {
|
||||||
|
string baseString = buf->base;
|
||||||
|
string Command = baseString.substr(0,baseString.find(" "));
|
||||||
|
string ogCommand = Command;
|
||||||
|
transform(Command.begin(), Command.end(), Command.begin(), ::tolower);
|
||||||
|
Command.erase( remove(Command.begin(), Command.end(), '\r'), Command.end() );
|
||||||
|
Command.erase( remove(Command.begin(), Command.end(), '\n'), Command.end() );
|
||||||
|
printf("It's a command: %s\n",Command.c_str());
|
||||||
|
if (Command == "@help") {
|
||||||
|
send_Message(client,(char *)"There is no help for you!\n");
|
||||||
|
printf("User wants help!\n");
|
||||||
|
}
|
||||||
|
if (Command == "@quit") {
|
||||||
|
send_Message(client,(char *)"Bye!\n");
|
||||||
|
uv_close((uv_handle_t*) client,(uv_close_cb) free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nread <= 0) {
|
||||||
|
printf("Read error %s\n",uv_err_name(nread));
|
||||||
|
uv_close((uv_handle_t*) client, (uv_close_cb) free);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_new_connection(uv_stream_t *server, int status) {
|
||||||
|
if (status == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
|
||||||
|
uv_tcp_init(loop, client);
|
||||||
|
if (uv_accept(server, (uv_stream_t*) client) == 0) {
|
||||||
|
printf("New Connection\n");
|
||||||
|
uv_read_start((uv_stream_t*) client, alloc_buffer, client_read);
|
||||||
|
send_Message((uv_stream_t*) client,(char *)"Welcome!\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uv_close((uv_handle_t*) client, (uv_close_cb) free);
|
||||||
|
printf("Dropping connection\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
\________↑_______________↑_______________↑_______________↑_______________↑_______________↑________/
|
||||||
|
END OF SECTION: LIBUV /
|
||||||
|
________________________________________________________________________________________________/
|
||||||
|
*/
|
29
src/socketserver.hpp
Normal file
29
src/socketserver.hpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
__ _____ _______ __ _____ ____ ___ ___
|
||||||
|
/ |/ / / / / ___// / / /__ \ / __ \__ \< /
|
||||||
|
/ /|_/ / / / /\__ \/ /_/ /__/ // / / /_/ // /
|
||||||
|
/ / / / /_/ /___/ / __ // __// /_/ / __// /
|
||||||
|
/_/ /_/\____//____/_/ /_//____/\____/____/_/
|
||||||
|
|
||||||
|
Copyright (C) 2021 MatCat
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <uv.h>
|
||||||
|
|
||||||
|
int setupSocketServer();
|
||||||
|
void send_Message(uv_stream_t* client, char* msg);
|
||||||
|
void on_new_connection(uv_stream_t *server, int status);
|
Loading…
Reference in New Issue
Block a user