#include #include #include #include #include #include #include #include #include ListenSocket::ListenSocket(int port) { is_good = true; _socket = socket(AF_INET, SOCK_STREAM, 0); if (_socket < 0) { int err = errno; std::ostringstream msg(""); msg << "Creating listen socket, error: " << strerror(err); debug(CRITICAL, msg.str()); is_good = false; return; } int on = 1; setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); if (bind(_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0) { int err = errno; std::ostringstream msg(""); msg << "Binding listen socket, error: " << strerror(err); debug(CRITICAL, msg.str()); is_good = false; return; } listen(_socket, 5); fcntl(_socket, F_SETFL, O_NONBLOCK); } ClientSocket *ListenSocket::get_client() { if (!good()) { return 0; } sockaddr_in addr; int addrsize = sizeof(addr); int c_socket; c_socket = accept(_socket, (sockaddr *) &addr, (socklen_t *) &addrsize); if (c_socket < 0) { return 0; } ClientSocket *client = new ClientSocket(c_socket, addr.sin_addr); clients.push_back(client); return client; } bool ListenSocket::wait_for_event(int timeout) { // Wait for event for timeout ms, return true if something occurred int count = clients.size() + 1; pollfd *fds; fds = new pollfd[count]; fds[0].fd = _socket; fds[0].events = POLLIN; fds[0].revents = 0; int i; for (i = 0; i < clients.size(); i++) { if (clients.at(i)->has_lines()) return true; clients.at(i)->fill_pollfd(fds[i + 1]); } int status = poll(fds, count, timeout); delete[] fds; if (status < 0) { debug(WARNING, "Poll error"); } return status != 0; // 0 == timeout } void ListenSocket::release_client(ClientSocket *client) { int i; for (i = 0; i < clients.size(); i++) { if (clients.at(i) == client) { clients.erase(clients.begin() + i); delete client; return; } } debug(CRITICAL, "Client to remove not in clients"); } bool ListenSocket::good() { return is_good; } ClientSocket::ClientSocket(int n_socket, in_addr naddr) { _socket = n_socket; is_good = true; addr = std::string(inet_ntoa(naddr)); buf = std::string(""); } ClientSocket::~ClientSocket() { close(_socket); } void ClientSocket::_recv() { char rawbuf[RECVBUF + 1] = {0}; int status = 0; status = recv(_socket, rawbuf, RECVBUF, MSG_DONTWAIT | MSG_NOSIGNAL); if (status < 0 && errno != EAGAIN) { is_good = false; return; } buf += std::string(rawbuf); } bool ClientSocket::getline(std::string &dest) { _recv(); if (!good()) { return false; } std::string::size_type pos = buf.find('\n'); if (pos == std::string::npos) { if (buf.size() > LINELENGTH) { debug(WARNING, "Line buffer overflow while receiving"); is_good = false; } return false; } dest = buf.substr(0, pos); buf = buf.substr(pos + 1); if (dest.at(dest.size() - 1) == '\r') { dest.erase(dest.size() - 1); } if (pos != 0) { // Empty line return true; } else { return false; } } void ClientSocket::putline(std::string line) { int status; line += "\n"; status = send(_socket, line.c_str(), line.size(), MSG_NOSIGNAL); if (status != line.size()) { is_good = false; } } bool ClientSocket::good() { return is_good; } bool ClientSocket::has_lines() { return buf.find('\n') != std::string::npos; } void ClientSocket::fill_pollfd(pollfd &fd) { fd.fd = _socket; fd.events = POLLIN; fd.revents = 0; } std::string ClientSocket::get_addr() { return addr; }