I’m stuck on Stage #QQ0
I am trying to run this program on CLion using WSL with Ubuntu 22 distro
What i am seeing is that when I send the command via telnet
*2\r\n$4\r\nECHO\r\n$9\r\nraspberry\r\n
C++ is inetrpretting \r\n as 4 characters.
this logic works fine in this way
if (buffer[position] != ‘\’ && buffer[position+1] != ‘r’ && buffer[position+2] != ‘\’ && buffer[position+3] != ‘n’)
But when I run it on code crafters \r is considered one char. Any idea how to fix it
Here are my logs:
Client connected
buffer[0]: *
buffer[1]: 2
buffer[2]: \
buffer[3]: r
buffer[4]: \
buffer[5]: n
buffer[6]: $
buffer[7]: 4
buffer[8]: \
buffer[9]: r
buffer[10]: \
buffer[11]: n
buffer[12]: E
buffer[13]: C
buffer[14]: H
buffer[15]: O
buffer[16]: \
buffer[17]: r
buffer[18]: \
buffer[19]: n
buffer[20]: $
buffer[21]: 9
buffer[22]: \
buffer[23]: r
buffer[24]: \
buffer[25]: n
buffer[26]: r
buffer[27]: a
buffer[28]: s
buffer[29]: p
buffer[30]: b
buffer[31]: e
buffer[32]: r
buffer[33]: r
buffer[34]: y
buffer[35]: \
buffer[36]: r
buffer[37]: \
buffer[38]: n
And here’s a snippet of my code:
#include <iostream>
#include <cstdlib>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <thread>
#include <vector>
using namespace std;
vector<string> processRESPCommand(string &buffer);
string processArray(vector<string> &command);
void handleRequest(int clientSocket)
{
string readBuffer;
while (true)
{
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
int recv_bytes = recv(clientSocket, buffer, 1024, 0);
if (recv_bytes == 0)
{
std::cout << "Client disconnected\n";
close(clientSocket);
return;
}
for (int i = 0; i < 40; i++) {
cout<<"buffer["<<i<<"]: "<<buffer[i]<<"\n";
}
readBuffer=buffer;
vector<string> command = processRESPCommand(readBuffer);
cout<<command[0]<<"\n";
const char *message = processArray(command).c_str();
send(clientSocket, message, strlen(message), 0);
}
}
int main(int argc, char **argv)
{
// Flush after every std::cout / std::cerr
std::cout << std::unitbuf;
std::cerr << std::unitbuf;
// You can use print statements as follows for debugging, they'll be visible when running tests.
std::cout << "Logs from your program will appear here!\n";
// test1();
// Uncomment this block to pass the first stage
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0)
{
std::cerr << "Failed to create server socket\n";
return 1;
}
// Since the tester restarts your program quite often, setting SO_REUSEADDR
// ensures that we don't run into 'Address already in use' errors
int reuse = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
std::cerr << "setsockopt failed\n";
return 1;
}
//
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(6379);
//
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
{
std::cerr << "Failed to bind to port 6379\n";
return 1;
}
//
int connection_backlog = 5;
if (listen(server_fd, connection_backlog) != 0)
{
std::cerr << "listen failed\n";
return 1;
}
struct sockaddr_in client_addr;
int client_addr_len = sizeof(client_addr);
std::cout << "Waiting for a client to connect...\n";
while (true)
{
int clientSocket = accept(server_fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_addr_len);
std::cout << "Client connected\n";
thread t(handleRequest, clientSocket);
t.detach();
}
close(server_fd);
return 0;
}
vector<string> processRESPCommand(string &buffer)
{
string local_buffer=buffer;
cout<<local_buffer<<"\n";
int position = 0;
vector<string> command;
vector<string> noValidCommand={"NVC"};
int sizeOfbuffer = buffer.size();
if (sizeOfbuffer < 1)
{
return noValidCommand;
}
if (buffer[position] != '*')
{
return {"nvc1"};
}
position++;
int commandLength = stoi(&buffer[position]);
position++;
if (buffer[position] != '\\' && buffer[position+1] != 'r' && buffer[position+2] != '\\' && buffer[position+3] != 'n')
{
cout<<"output: "<<buffer[position]<<buffer[position+1]<<buffer[position+2]<<buffer[position+3]<<"\n";
return {"nvc2"};
}
position += 4;
for (int i = 0; i < commandLength; i++)
{
if (buffer[position] != '$')
{
return {"nvc3"};
}
position++;
int tokenLength = stoi(&buffer[position]);
position++;
if (buffer[position] != '\\' && buffer[position+1] != 'r' && buffer[position+2] != '\\' && buffer[position+3] != 'n')
{
return {"nvc4"};
}
position += 4;
command.push_back(buffer.substr(position, tokenLength));
position += tokenLength;
vector<string> gg;
gg.push_back(to_string(buffer.size()));
if (buffer[position] != '\\' && buffer[position+1] != 'r' && buffer[position+2] != '\\' && buffer[position+3] != 'n')
{
return command;
}
position += 4;
}
cout<<"Command1: "<<command[0]<<endl;
return command;
}
string processArray(vector<string> &command) {
if (command[0]=="PING") {
return "$4\r\nPONG\r\n";
}
if (command[0]=="ECHO") {
return "$"+to_string(command[1].size())+"\r\n"+command[1]+"\r\n";;
}
}