Skip to content

Commit

Permalink
feat(poll): implement client timeout + add tester
Browse files Browse the repository at this point in the history
  • Loading branch information
dantol29 committed May 22, 2024
1 parent a018b78 commit fb0eaa3
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 12 deletions.
18 changes: 18 additions & 0 deletions src/Connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Connection::Connection(struct pollfd &pollFd, Server &server)
_CGIHasCompleted = false;
_CGIHasTimedOut = false;
_CGIHasReadPipe = false;
_startTime = 0;
}

Connection::Connection(const Connection &other)
Expand Down Expand Up @@ -58,6 +59,8 @@ Connection::Connection(const Connection &other)
_CGIHasCompleted = other._CGIHasCompleted;
_CGIHasTimedOut = other._CGIHasTimedOut;
_CGIHasReadPipe = other._CGIHasReadPipe;
_cgiOutputBuffer = other._cgiOutputBuffer;
_startTime = other._startTime;
// std::cout << "Connection object copied" << std::endl;
}

Expand Down Expand Up @@ -90,6 +93,8 @@ Connection &Connection::operator=(const Connection &other)
_CGIHasCompleted = other._CGIHasCompleted;
_CGIHasTimedOut = other._CGIHasTimedOut;
_CGIHasReadPipe = other._CGIHasReadPipe;
_cgiOutputBuffer = other._cgiOutputBuffer;
_startTime = other._startTime;
}
std::cout << "Connection object assigned" << std::endl;
return *this;
Expand Down Expand Up @@ -232,8 +237,18 @@ std::string Connection::getCGIOutputBuffer() const
return _cgiOutputBuffer;
}

time_t Connection::getStartTime() const
{
return _startTime;
}

// SETTERS

void Connection::setStartTime(time_t time)
{
_startTime = time;
}

void Connection::setCGIOutputBuffer(std::string buffer)
{
_cgiOutputBuffer = buffer;
Expand Down Expand Up @@ -358,8 +373,11 @@ bool Connection::readHeaders(Parser &parser)
}
else if (bytesRead == 0)
{
// TODO: think about it
std::cout << "Connection closed before headers being completely sent" << std::endl;
return false;
// std::cout << "bytes_read == 0" << std::endl;
// return true;
}
else
{
Expand Down
3 changes: 3 additions & 0 deletions src/Connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Connection
size_t _responseSize;
size_t _responseSizeSent;
std::string _responseString;
time_t _startTime;
bool _hasCGI;
bool _CGIHasExited;
pid_t _CGIPid;
Expand Down Expand Up @@ -85,6 +86,7 @@ class Connection
unsigned short getServerPort() const;
size_t getResponseSize() const;
size_t getResponseSizeSent() const;
time_t getStartTime() const;

bool getHasReadSocket() const;
bool getHasFinishedReading() const;
Expand Down Expand Up @@ -116,6 +118,7 @@ class Connection
void setCanBeClosed(bool value);
void setHasDataToSend(bool value);
void setHasFinishedSending(bool value);
void setStartTime(time_t startTime);

void setHasCGI(bool value);
void setCGIPid(pid_t pid);
Expand Down
39 changes: 34 additions & 5 deletions src/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Server::Server(const Config &config, EventManager &eventManager) : _config(confi
_serverSockets = std::vector<ServerSocket>();
_hasCGI = false;
_CGICounter = 0;
_clientCounter = 0;
Debug::log("Server created with config constructor", Debug::OCF);
}

Expand Down Expand Up @@ -71,16 +72,21 @@ void Server::startPollEventLoop()
while (1)
{
if (_hasCGI)
timeout = 500; // 1 seconds
timeout = 1000; // 1 seconds
else if (_clientCounter > 0)
{
std::cout << BLUE << "Client counter: " << _clientCounter << RESET << std::endl;
timeout = 5000; // 15 seconds
}
else
timeout = -1;
timeout = -1; // infinite
// printConnections("BEFORE POLL", _FDs, _connections, true);
std::cout << CYAN << "++++++++++++++ #" << pollCounter
<< " Waiting for new connection or Polling +++++++++++++++" << RESET << std::endl;
int ret = poll(_FDs.data(), _FDs.size(), timeout);
pollCounter++;
// printFrame("POLL EVENT DETECTED", true);
// printConnections("AFTER POLL", _FDs, _connections, true);
printFrame("POLL EVENT DETECTED", true);
printConnections("AFTER POLL", _FDs, _connections, true);
if (ret > 0)
{
size_t originalSize = _FDs.size();
Expand All @@ -93,6 +99,9 @@ void Server::startPollEventLoop()
acceptNewConnection(_connections[i]);
else
{
if (_FDs[i].revents & (POLLIN))
_connections[i].setStartTime(time(NULL));

handleConnection(_connections[i], i);
if ((_connections[i].getHasFinishedReading() && _connections[i].getHasDataToSend()))
_FDs[i].events = POLLOUT;
Expand All @@ -112,7 +121,6 @@ void Server::startPollEventLoop()
else
handlePollError();

std::cout << "Has CGI: " << (_hasCGI ? "true" : "false") << std::endl;
if (_hasCGI)
waitCGI();
}
Expand Down Expand Up @@ -453,6 +461,7 @@ void Server::closeClientConnection(Connection &conn, size_t &i)
close(conn.getPollFd().fd);
_FDs.erase(_FDs.begin() + i);
_connections.erase(_connections.begin() + i);
--_clientCounter;
--i;
}

Expand Down Expand Up @@ -738,6 +747,7 @@ void Server::acceptNewConnection(Connection &conn)
/* start together */
_FDs.push_back(newSocketPoll);
_connections.push_back(newConnection);
++_clientCounter;
std::cout << newConnection.getHasFinishedReading() << std::endl;
std::cout << _connections.back().getHasFinishedReading() << std::endl;
/* end together */
Expand Down Expand Up @@ -807,6 +817,25 @@ void Server::handleSocketTimeoutIfAny()
{
// Is not the socket timeout, but the poll timeout
std::cout << "Timeout occurred!" << std::endl;

// loop through the connections and check for timeout
for (size_t i = 0; i < _FDs.size(); i++)
{
if (_connections[i].getType() == SERVER || _connections[i].getStartTime() == 0)
continue;

double elapsed = difftime(time(NULL), _connections[i].getStartTime());
if (elapsed > 3)
{
std::cout << RED << "Elapsed time: " << elapsed << " seconds" << RESET << std::endl;
// We have to send a 408 Request Timeout
_connections[i].getResponse().setStatusCode(408, "Request Timeout");
buildResponse(_connections[i], i, _connections[i].getRequest(), _connections[i].getResponse());
writeToClient(_connections[i], i, _connections[i].getResponse());
// we have to close the connection
closeClientConnection(_connections[i], i);
}
}
// This should never happen with an infinite timeout
}

Expand Down
3 changes: 1 addition & 2 deletions src/Server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@ class Server
std::vector<std::pair<int, int> > _pipeFDs;
// clang-format on
EventManager &_eventManager;

int _clientCounter;
bool _hasCGI;

int _CGICounter;

/*** Private Methods ***/
Expand Down
10 changes: 5 additions & 5 deletions tests/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ void sendData(const std::vector<HTTPTest> &tests, sockaddr_in serverAddress)
ssize_t bytesSent = send(clientSocket, test.request.c_str(), test.request.size(), 0);

char buffer[BUFFER_SIZE];
if (waitForResponseWitPoll(clientSocket, POLL_TIMOUT))
if (waitForResponseWitPoll(clientSocket, POLL_TIMOUT * 100))
{
ssize_t bytesRead = read(clientSocket, buffer, BUFFER_SIZE);
if (bytesRead < 0)
Expand Down Expand Up @@ -210,7 +210,7 @@ void headers(sockaddr_in serverAddress)
HTTPTest("GET / HTTP/1.1\r\nRandom: www.example.com\r\n\r\n", "400"),
HTTPTest("GET / HTTP/1.1\r\nHost www.example.com\r\n\r\n", "400"),
HTTPTest("GET / HTTP/1.1\r\nHost:: www.example.com\r\n\r\n", "400"),
// TODO: HTTPTest("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r", "400"),
HTTPTest("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r", "408"),
HTTPTest("GET / HTTP/1.1\r\nHost:www.example.com\r\n\r\n", "400"),
HTTPTest("GET / HTTP/1.1\r\n Host: www.example.com\r\n\r\n", "400"),
HTTPTest("GET /HTTP/1.1\r\nHo st: www.example.com\r\n\r\n", "400"),
Expand Down Expand Up @@ -281,18 +281,18 @@ int main(int argc, char **argv)

// if (std::strcmp(argv[1], "query") == 0)
std::cout << "\033[38;5;214mRunning query tests\033[0m" << std::endl;
query(serverAddress);
// query(serverAddress);
// else if (std::strcmp(argv[1], "simple") == 0)
std::cout << "\033[38;5;214mQuery tests done\033[0m" << std::endl;
std::cout << "\033[38;5;214mRunning simple tests\033[0m" << std::endl;
simple(serverAddress);
// simple(serverAddress);
std::cout << "\033[38;5;214mSimple tests done\033[0m" << std::endl;
std::cout << "\033[38;5;214mRunning headers tests\033[0m" << std::endl;
// else if (std::strcmp(argv[1], "headers") == 0)
headers(serverAddress);
std::cout << "\033[38;5;214mHeaders tests done\033[0m" << std::endl;
// else if (std::strcmp(argv[1], "body") == 0)
body(serverAddress);
// body(serverAddress);
// else
// std::cout << "Invalid test name" << std::endl;
if (is_error)
Expand Down

0 comments on commit fb0eaa3

Please sign in to comment.