#include "Webserv.hpp" Webserv::Webserv() { int on = 1; std::cout << "Server init\n"; // create socket descriptor _socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (_socket_fd == -1) { ::perror("err socket()"); throw std::runtime_error("Socket init"); } // allow socket descriptor to be reuseable if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) { ::perror("setsockopt() failed"); throw std::runtime_error("Socket init"); } } Webserv::~Webserv() { std::cout << "Server destroyed\n"; } void Webserv::bind(in_port_t port) { struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = ::htons(port); addr.sin_addr.s_addr = ::htonl(INADDR_ANY); if (::bind(_socket_fd, (const sockaddr*)&addr, sizeof addr) == -1) { ::perror("err bind(): "); throw std::runtime_error("Socket bind"); } } void Webserv::listen(unsigned int max_connections) { if (::listen(_socket_fd, max_connections) == -1) { ::perror("err listen(): "); throw std::runtime_error("Socket listen"); } } #define BUFSIZE 8192 #define MSG_TEST "Le Webserv / 20 =D\n" #define MSG_BOUNCE "bounced properly ;)\n" // placeholder void Webserv::_add_fd(int sd, short event) { struct pollfd new_poll_fd; new_poll_fd.fd = sd; new_poll_fd.events = event; new_poll_fd.revents = 0; _fds.push_back(new_poll_fd); } //void Webserv::_accept_sockets(int sd, short event) //{ //} void Webserv::start(int timeout) { int len; int rc; int new_sd = -1; char buffer[80]; int current_size = 0; int end_server = FALSE; int compress_array = FALSE; int close_conn; struct pollfd * fds_ptr; // init first struct _add_fd(_socket_fd, POLLIN); // init pointer on first element of vector of struct pollfd fds_ptr = &_fds[0]; std::cout << "Server started\n"; while (end_server == FALSE) { _nfds = _fds.size(); poll(fds_ptr, _nfds, timeout); current_size = _nfds; for (int i = 0; i < current_size; i++) { if(_fds[i].revents == 0) { std::cout << "here\n"; continue; } if(_fds[i].revents != POLLIN) { printf(" Error! revents = %d\n", _fds[i].revents); end_server = TRUE; break; } if (_fds[i].fd == _socket_fd) { printf(" Listening socket is readable\n"); do { new_sd = accept(_socket_fd, NULL, NULL); if (new_sd < 0) { printf(" new_sd < 0, = %i\n", new_sd); if (errno != EWOULDBLOCK && errno != EAGAIN) { perror(" accept() failed"); end_server = TRUE; } break; } printf(" New incoming connection - %d\n", new_sd); _add_fd(new_sd, POLLIN); } while (new_sd != -1); } else { printf(" Descriptor %d is readable\n", _fds[i].fd); close_conn = FALSE; do { rc = recv(_fds[i].fd, buffer, sizeof(buffer), 0); if (rc < 0) { if (errno != EWOULDBLOCK) { perror(" recv() failed"); close_conn = TRUE; } break; } if (rc == 0) { printf(" Connection closed\n"); close_conn = TRUE; break; } len = rc; printf(" %d bytes received\n", len); rc = send(_fds[i].fd, buffer, len, 0); if (rc < 0) { perror(" send() failed"); close_conn = TRUE; break; } } while(TRUE); if (close_conn) { close(_fds[i].fd); _fds[i].fd = -1; compress_array = TRUE; } } // else } // for (i = 0; i < current_size; i++) if (compress_array) { compress_array = FALSE; for (int i = 0; i < _nfds; i++) { if (_fds[i].fd == -1) { // for(int j = i; j < nfds; j++) // { // fds[j].fd = fds[j+1].fd; // } _fds.erase(_fds.begin() + i); i--; // nfds--; } } } } // while (end_server == FALSE) } /* struct sockaddr_in addr; socklen_t addr_len; int accepted_fd; struct pollfd poll_s; char buf[BUFSIZE]; // WIP buffer. need to try with std::vector or std::string. int ret; std::cout << "----------\n"; std::cout << "accept()\n"; addr_len = sizeof addr; accepted_fd = ::accept(_socket_fd, (sockaddr*)&addr, &addr_len); if (accepted_fd == -1) { ::perror("err accept(): "); continue; } // "Your server must never block and the client can be bounced properly if necessary". // NO-Block OK, but how to handle it ? Miss the bouncing part. ::fcntl(accepted_fd, F_SETFL, O_NONBLOCK); std::cout << "poll()\n"; // poll (or equivalent) poll_s.fd = accepted_fd; poll_s.events = POLLIN; // We need a way to valid POLLOUT and POLLIN at the same time (both, not one of them) ::poll(&poll_s, 1, -1); std::cout << "recv()\n"; ret = ::recv(accepted_fd, buf, BUFSIZE, 0); if (ret == -1) { ::perror("err recv(): "); if (::send(accepted_fd, MSG_BOUNCE, sizeof MSG_BOUNCE - 1, 0) == -1) ::perror("err send(): "); ::close(accepted_fd); continue; } buf[ret] = '\0'; std::cout << "send()\n"; if (::send(accepted_fd, buf, ret, 0) == -1) // echo the read ::perror("err send(): "); if (::send(accepted_fd, MSG_TEST, sizeof MSG_TEST - 1, 0) == -1) ::perror("err send(): "); ::close(accepted_fd); */