0

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;
}
  • 3
    [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) – Jesper Juhl Jun 26 '23 at 11:11
  • Minimize your problem. You know the specific data is causing a problem. Test with that and reduce until you see the problem. Likely an exception is being raised, but something may be causing undefined behaviour. Also, repeating for the millionth time (not your fault, obviously), Boost PropertyTree is **not a JSON library**. Any reason not to just use Boost JSON? – sehe Jun 26 '23 at 11:13
  • Just because this is where the program crashes or reports an error doesn't mean this is where the problem is. C++ does not work this way. The problem can be anywhere in your code, but after the bug occurs the program keeps running for a little bit before it finally crashes here. This is why stackoverflow.com's [help] requires you to show a [mre] that everyone else can cut/paste ***exactly as shown***, then compile, run, and reproduce your problem. See [ask] for more information. Until you do that, it is unlikely that anyone will be able to answer your question. – Sam Varshavchik Jun 26 '23 at 11:18
  • Do you have some specific reason for using raw TCP and C++? Using a higher level protocol, like MQTT, gRPC, or similar should be easier, and likely more reliable, than using plain TCP. I would probably also argue that C# is easier to use than C++, at least you tend to get more reasonable error messages. – JonasH Jun 26 '23 at 12:08
  • I am making this application this way for my project which focuses on the security of a multiplayer application. – PAVAN PRASAD 2022 Jun 27 '23 at 08:00

1 Answers1

-1

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:

std::string BufferToString(tcp::socket& socket, std::string& route, std::string& Method) {

boost::beast::flat_buffer request_buffer;
boost::beast::http::request<boost::beast::http::string_body> request;
boost::system::error_code error;

try
{
    boost::beast::http::read(socket, request_buffer, request, 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 " ";
}

Method = request.method_string();
route = request.target();

std::string request_data = request.body();
return request_data;}

This uses the in-built parser and handles whatever memory problem that I might've been facing ( which I couldn't figure out )