I am building a complete multiplayer application with 2 servers of nodejs and C++, the problem in the C++ server is that as soon as a client from the Unity client connects and sends the userdata, the server has a segmentation fault and exits without any messages.
I am using HTTP TCP protocol for communication and using the code below as the main function
int main() {
boost::asio::io_context io_context;
std::string raw_ip_address = "0.0.0.0";
boost::system::error_code ec;
boost::asio::ip::address ip_address =
boost::asio::ip::address::from_string(raw_ip_address, ec);
if (ec.value() != 0) {
// Provided IP address is invalid. Breaking execution.
std::cout
<< "Failed to parse the IP address. Error code = "
<< ec.value() << ". Message: " << ec.message();
return ec.value();
}
tcp::endpoint tp(ip_address, 8081);
tcp::acceptor acceptor(io_context, tp);
Rooms MainRooms;
while (true) {
tcp::socket socket(io_context);
acceptor.accept(socket);
RouteRequest(socket, MainRooms);
}
return 0;
}
I cannot recreate this problem with postman.
void RouteRequest(tcp::socket& socket, Rooms& rooms) {
std::string route = "/";
std::string Method;
//this is always set to process this
//better to use json everywhere
//easier to hack too
//hopefully security stuff can work here
std::string request_data = BufferToString(socket, route, Method);
//std::cout << Method << "THis is method" << std::endl;
//std::cout << route << "THis is Route" << std::endl;
//std::cout << request_data << std::endl;+ Current {username="" accessToken="" Room=0 ...} Player
//always send a response
std::string response;
if (Method.compare("POST") == 0) {
if (route.compare("/") == 0) {
try
{
Player Current = Player(request_data);
if (rooms.addRoomMate(Current)) {
sendHttpResponse(response, 200, "text/html", "Person Added!");
Current.printDetails();
}
else {
sendHttpResponse(response, 200, "text/html", "Person Exists!");
}
}
catch (const std::exception& e)
{
throw e.what();
std::cout << e.what() << std::endl;
sendHttpResponse(response, 500, "text/html", e.what());
}
}
It seems that sometimes the request_data does not have it's json
I tried to check the values before sending , during transit and after reaching the C++ server . Before Sending : in the C# client the code is :
private IEnumerator Post(string url, string bodyJsonString)
{
var request = new UnityWebRequest(URL + url, "POST");
byte[] bodyRaw = Encoding.UTF8.GetBytes(bodyJsonString);
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
//Debug.Log(Encoding.ASCII.GetString(bodyRaw));
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
//Debug.Log("Status Code: " + request.responseCode);
//Debug.Log(request.downloadHandler.text);
}
private void SendWithDetails()
{
SendData();
string json = JsonUtility.ToJson(ThisData);
Debug.Log("Sending");
Debug.Log(json);
StartCoroutine(Post("update", json));
}
private void FixedUpdate()
{
if (isLoggedIn == true)
{
SendWithDetails();
}
}
void SendData()
{
//we just need w and y
float x =ThisPlayer.transform.position.x;
float y = ThisPlayer.transform.position.y;
float z = ThisPlayer.transform.position.z;
float v = ThisPlayer.transform.eulerAngles.x;
float u = ThisPlayer.transform.eulerAngles.y;
float w = ThisPlayer.transform.eulerAngles.z;
x = Mathf.FloorToInt(1000 * x) / 1000;
y = Mathf.FloorToInt(1000 * y) / 1000;
z = Mathf.FloorToInt(1000 * z) / 1000;
u = Mathf.FloorToInt(1000 * u) / 1000;
v = Mathf.FloorToInt(1000 * v) / 1000;
w = Mathf.FloorToInt(1000*x)/1000;
Debug.Log("Added data");
ThisData.QuickAssign(x, y, z, u, v, w);
}
I checked that all the variable and the byte array are perfectly correct.
Then in transit I checked it withe Wireshark, No problem there. The function that I am using to get the json string from the socket is
std::string BufferToString(tcp::socket& socket, std::string& route, std::string& Method) {
boost::asio::streambuf request_buffer;
boost::system::error_code error;
try
{
boost::asio::read_until(socket, request_buffer, "\r\n\r\n", error);
if (error) {
throw std::runtime_error(error.message()); // Rethrow the error as an exception
}
}
catch (const std::exception& ex)
{
std::cout << "Exception occurred: " << ex.what() << std::endl;
return " ";
}
std::string request_data(boost::asio::buffers_begin(request_buffer.data()),
boost::asio::buffers_end(request_buffer.data()));
std::size_t path_start = request_data.find(" ");
if (path_start != std::string::npos) {
std::size_t path_end = request_data.find(" ", path_start + 1);
route = request_data.substr(path_start + 1, path_end - path_start - 1);
}
else {
std::cout << "String error: \n" << request_data << std::endl;
}
Method = request_data.substr(0, request_data.find(" "));
return request_data;
}
The std::string function find() was giving an unnatural value to the start_pos variable.Also the request_data would have an empty body. Instead of that I used the code:
This uses the in-built parser and handles whatever memory problem that I might've been facing ( which I couldn't figure out )