I'm trying to create an HTTP server using C++ 98.
The issue is that, every time I launch my server, I get the response, sending again the request from the same browser tab, and the browser keeps loading. In my kqueue, it seems like the block for checking the read event is not being executed on the second time.
This is my code:
void webserv::Server::lunch(){
this->kq.create_event(this->sock.getSocket(), EVFILT_READ);
while(1)
this->_lunch_worker();
}
void webserv::Server::_lunch_worker(void)
{
int n_ev;
int accept_sock;
int address_size;
char buff[1000];
webserv::Header header;
// register the events in ev_list
std::cout << GREEN << "---- WAITING FOR CONNECTION ----" << RESET << std::endl;
n_ev = this->kq.get_event();
for (int i = 0; i < n_ev; i++)
{
if (this->kq.get_fd(i) < 0)
continue;
if (this->kq.get_fd(i) == this->sock.getSocket())
{
std::cout << "--- RECEIVED NEW CONNECTION ---" << std::endl;
address_size = sizeof(this->sock.getAddress());
accept_sock = accept(
this->sock.getSocket(),
(struct sockaddr*)&this->sock.getAddress(),
(socklen_t *)&address_size
);
this->sock.test_error(accept_sock);
this->kq.create_event(accept_sock, EVFILT_READ);
int flags;
if ((flags = fcntl(accept_sock, F_GETFL, 0)) < 0) {
perror("fcntl");
close(accept_sock);
close(this->sock.getSocket());
}
if (fcntl(accept_sock, F_SETFL, flags | O_NONBLOCK) < 0) {
perror("fcntl");
close(accept_sock);
close(this->sock.getSocket());
}
this->kq.create_event(accept_sock, EVFILT_WRITE, EV_ADD | EV_ONESHOT);
}
else if (this->kq.is_read_available(i))
{
int bytes_read;
std::cout << "START: is_read_available" << std::endl;
if ((bytes_read = recv(this->kq.get_fd(i), buff, 999, 0)) > 0)
{
}
}
else if (this->kq.is_write_available(i))
{
std::string hello = "HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: 12\n\nHello world!";
if (send(this->kq.get_fd(i), hello.c_str(), hello.length(), 0) != 0)
{
std::cout << "TEST2" << std::endl;
this->kq.set_event(this->kq.get_fd(i), EVFILT_WRITE, EV_DELETE);
this->kq.get_event_list()[i].ident = -1;
close(this->kq.get_fd(i));
}
std::cout << "END: is_write_available" << std::endl;
}
}
}
And this is the kqueue class:
/************************ CONSTRUCTORS/DESTRUCTOR ************************/
webserv::Kqueue::Kqueue()
{
this->_kq = kqueue();
std::cout << "KQUEUE CREATED" << std::endl;
this->test_error(this->_kq, "Creating Kqueue :");
this->_n_ev = 0;
}
webserv::Kqueue::~Kqueue()
{
close(this->_kq);
}
/************************ MEMBER FUNCTIONS ************************/
void webserv::Kqueue::set_event(int fd, int filter, int flags, void *udata)
{
EV_SET(&this->_ev_set, fd, filter, flags, 0, 0, udata);
}
void webserv::Kqueue::add_event(void)
{
int ret;
ret = kevent(this->_kq, &this->_ev_set, 1, NULL, 0, NULL);
this->test_error(ret, "Kqueue/add_even functions");
}
int webserv::Kqueue::get_event(void)
{
this->_n_ev = kevent(this->_kq, NULL, 0, this->_ev_list, __EV_LIST_SIZE__, NULL);
this->test_error(this->_n_ev, "Kqueue/get_event function:");
return (this->_n_ev);
}
void webserv::Kqueue::create_event(int fd, int filter, int flags, void *udata)
{
this->set_event(fd, filter, flags, udata);
this->add_event();
}
bool webserv::Kqueue::isEOF(int index)
{
if (this->_n_ev <= index)
this->test_error(-1, "Kqueue/isEOF function:");
return (this->_ev_list[index].flags & EV_EOF);
}
bool webserv::Kqueue::is_read_available(int index)
{
if (this->_n_ev <= index)
this->test_error(-1, "Kqueue/is_read_available function:");
return (this->_ev_list[index].filter == EVFILT_READ);
}
bool webserv::Kqueue::is_write_available(int index)
{
if (this->_n_ev <= index)
this->test_error(-1, "Kqueue/is_write_available function:");
return (this->_ev_list[index].filter == EVFILT_WRITE);
}
void webserv::Kqueue::test_error(int fd, const std::string &str)
{
if (fd < 0)
{
std::cerr << RED << str << " ";
perror("The following error occured: ");
std::cerr << RESET;
exit(EXIT_FAILURE);
}
}
/************************ GETTERS/SETTERS ************************/
struct kevent *webserv::Kqueue::get_event_list()
{
return (this->_ev_list);
}
int webserv::Kqueue::get_fd(int index)
{
if (this->_n_ev <= index)
this->test_error(-1, "Kqueue/get_ev_list function:");
return (this->_ev_list[index].ident);
}
void webserv::Kqueue::set_kqueue(int fd)
{
this->_kq = fd;
}