#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"); } } 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::_close_fd(int i) { close(_fds[i].fd); _fds[i].fd = -1; _fds.erase(_fds.begin() + i); } void Webserv::_accept_connection() { int new_sd = 0; printf(" Listening socket is readable\n"); while (new_sd != -1) { new_sd = accept(_socket_fd, NULL, NULL); if (new_sd < 0) { if (errno != EWOULDBLOCK && errno != EAGAIN) { ::perror("err accept()"); throw std::runtime_error("Socket accept"); } break; } printf(" New incoming connection - %d\n", new_sd); _add_fd(new_sd, POLLIN); } } void Webserv::_connect_socket(int i, int bufsize) { int len; int ret; std::vector buffer(bufsize); printf(" Descriptor %d is readable\n", _fds[i].fd); while (TRUE) { ret = recv(_fds[i].fd, &buffer[0], buffer.size(), 0); if (ret < 0) { if (errno != EWOULDBLOCK) { ::perror(" recv() failed"); _close_fd(i); } break; } if (ret == 0) { printf(" Connection closed\n"); _close_fd(i); break; } len = ret; printf(" %d bytes received\n", len); ret = send(_fds[i].fd, &buffer[0], len, 0); if (ret < 0) { ::perror(" send() failed"); _close_fd(i); break; } } } void Webserv::start(int timeout, int bufsize) { _add_fd(_socket_fd, POLLIN); std::cout << "Server started\n"; while (TRUE) { printf("-----------\npoll\n"); poll(&_fds[0], _fds.size(), timeout); for (unsigned int i = 0; i < _fds.size(); i++) { if(_fds[i].revents == 0) continue; if(_fds[i].revents != POLLIN) { ::perror("err revents"); throw std::runtime_error("Socket poll"); } if (_fds[i].fd == _socket_fd) _accept_connection(); else _connect_socket(i, bufsize); } } }