c++socketstcpnetwork-programmingchallenge-response

BackToSchool - TCP; root-me; should work but doesn't - c++ C++


I am trying to solve a root-me.org challenge, it is a pretty easy one but i am still stuck and cannot figure out what the problem is. The problem :

Statement

To start this test using the TCP protocol, you need to connect to a program on a network socket.

Calculate the square root of number 1 and multiply by number 2.

Then round the result to two decimal places.

You have 2 seconds to send the correct answer from the moment the program sends you the calculation.

The answer must be sent in the form of int

According to what I have discovered so far the issue lies with the part where I try to send my response to the server.

Link to the challenge I am trying to solve : https://www.root-me.org/en/Challenges/Programming/TCP-Back-to-school

I have tried four different ways to send the answer to send my answer : using a float, a string and an integer, at one point only I got a response from the server, it said that I sended the wrong type, "answer has to be int or float", I don't even remember how I did to get that response.

Additionally, note that I am only able to send strings with the right value and precision as floats lack too much precision in c++. For example: sending doubles results in sending a number with the right precision (38559.390000) but the decimals are filled up by "0" sending float results in wrong result : (8807.008807) sending string works but apparently the server doesn't support it.

My code :

// TCP - Retour au collège
#include <sys/socket.h> 
#include <iostream>
#include <cmath>
#include <cstring>
#include <netinet/in.h>
#include <unistd.h>
#include <iomanip>
#include <arpa/inet.h>
#include <string>

int main() {
    // Connect to root-me.org with tcp (this script is client side)
    int client = socket(AF_INET6, SOCK_STREAM, 0);
    
    // set socket address type to network type 
    struct sockaddr_in6 serv;
    std::memset(&serv, 0, sizeof(serv));
    // set type to ipv6
    serv.sin6_family = AF_INET6;
    // Set port
    serv.sin6_port = htons(52002);
    //convert to bin and add actual adress
    inet_pton(AF_INET6, "2001:bc8:35b0:c166::151", &serv.sin6_addr);
    
    // Bind the client to the parameters
    connect(client, (struct sockaddr*)&serv, sizeof(serv)); 
    std::cout << "port 52002" << std::endl;
    
    //Receive data and processing
    char buffer[1024] = { 0 }; 
    recv(client, buffer, sizeof(buffer), 0); 
    std::cout << "Message from serv: " << buffer << std::endl;
    std::string str = buffer;
    size_t startPos1 = str.find("square root of ") + strlen("square root of ");
    size_t startPos2 = str.find(" and multiply by ") + strlen(" and multiply by ");
    size_t endPos1 = str.find(" and multiply by ") - 1;
    size_t endPos2 = str.find(" =") - 1;
    std::string number1 = str.substr(startPos1, endPos1 - startPos1 + 1);
    int number1_ = std::stoi(number1);
    std::string number2 = str.substr(startPos2, endPos2 - startPos2 + 1);
    int number2_ = std::stoi(number2);
    double res = (std::sqrt((number1_))) * number2_; //static_cast<double>
    std::cout << std::setprecision (15) << res << std::endl;
    
    
    //seend - HERE I TRIED MANY DIFFERENT THINGS, SENDING A STRING, A DOUBLE AND A FLOAT
    //float res_ = static_cast<float>(res);
    //std::cout << res_ << std::endl;
    //std::string res_=std::to_string(res);
    //res_.erase(res_.size() - 4);
    //std::cout << "string:" << res_ << std::endl;
    //char buffer2[sizeof(res_)];
    //std::memcpy(buffer2, &res_, sizeof(res_));
    res = std::ceil(res * 100.0) / 100.0;
    std::string a = std::to_string(res);
    size_t pos = (a.find(".")+3);
    std::string b = a.substr(0, pos);
    std::cout << b << std::endl;
    const char* message = b.c_str(); 
    send(client, message, strlen(b.c_str()), 0); 
    std::cout << "sent :" << b.c_str() << ";" << message << std::endl;
    
    //Response?
    char buffer1[1024] = { 0 }; 
    recv(client, buffer1, sizeof(buffer1), 0); 
    std::cout << "Message from serv: " << buffer1 << std::endl;
   
    //closing&ending
    close(client); 
    return 0;
}


The outputs : THE ONLY TIME I GOT A RESPONSE FROM SERV :

port 52002
Message from serv: 
====================
 GO BACK TO COLLEGE
====================
You should tell me the answer of this math operation in less than 2 seconds !

Calculate the square root of 1 and multiply by 8807 = 
8807.00
sent :8807.008807
Message from serv: [!] Please only send int/float !

Out 1 -

port 52002
Message from serv: 
==================== GO BACK TO COLLEGE====================
You should tell me the answer of this math operation in less than 2 seconds !
Calculate the square root of 207 and multiply by 2092 = 
30098.6386403106
sent :30098.64

Out 2 -

port 52002
Message from serv: 
====================
 GO BACK TO COLLEGE
====================
You should tell me the answer of this math operation in less than 2 seconds !

Calculate the square root of 120 and multiply by 3958 = 
43357.7176521089
43357.72
sent :43357.72;43357.72

Out 3 -

port 52002
Message from serv: 
====================
 GO BACK TO COLLEGE
====================
You should tell me the answer of this math operation in less than 2 seconds !

Calculate the square root of 87 and multiply by 4134 = 
38559.3850054692
string:38559.39
sent :38559.39;38559.390000

Out 4 -

port 52002
Message from serv: 
====================
 GO BACK TO COLLEGE
====================
You should tell me the answer of this math operation in less than 2 seconds !

Calculate the square root of 56 and multiply by 9112 = 
68187.9642165683
68187.97sent :68187.97;R�����@R�����@�x�


Solution

  • Okay, I actually solved it by coding the solution in python and thus unlocking the "solutions" category of website where I could find a version of the code in C that i used to inspire me.

    Here is basically what I did (without spoiling) :

    First I deleted the part between the two following code samples and restarted from scratch for the sending of the data as it is just an enormous mess

    double res = (std::sqrt((number1_))) * number2_; //static_cast<double>
    std::cout << std::setprecision (15) << res << std::endl;
    

    ===============================DELETE=========================================

    //Response?
    char buffer1[1024] = { 0 }; 
    

    At the end of the processing of the data I output a double double res = (std::sqrt((number1_))) * number2_; //static_cast<double>

    After what I use "osstring":std::ostringstream oss; to define "oss", i then assign the double "res" to "oss" (something like oss << [...] << std::setprecision(2) << res) That forces the string "oss" to have 2 decimals and they are accurate because I was using a double, which is more accurate than a float object in c++.

    I then send back my data (after changing it from oss to a std::string ofc) : send(client, strn.c_str(), strlen(strn), 0);

    Finally, I listen for the servers response as shown in the code above.