// This file is part of Timmi. // // Timmi is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. #include #include #include #include #include #include #include #include const int RECVBUF = 1024; // Amount of data to receive at one go const int LINELENGTH = 4096; // Maximum line length TCPSocket::TCPSocket(int fd, std::string addr): fd_(fd), addr_(addr), buf_(""), good_(true) { } TCPSocket::~TCPSocket() { shutdown(fd_, SHUT_RDWR); close(fd_); } int TCPSocket::getfd() const { return fd_; } std::string TCPSocket::getaddr() const { return addr_; } bool TCPSocket::good() const { return good_; } bool TCPSocket::wait_for_event(int timeout) const { pollfd fds[1] = {{fd_, POLLIN, 0}}; int status = poll(fds, 1, timeout); if (status < 0) { debug_with_errno(WARNING, "Poll error"); } return status != 0; // 0 == timeout } bool TCPSocket::getline(std::string &line) { int pos = buf_.find("\n"); if (pos == std::string::npos) { receive_(); pos = buf_.find("\n"); if (pos == std::string::npos) { return false; } } line = buf_.substr(0, pos); buf_ = buf_.substr(pos + 1); // Skip \n return true; } void TCPSocket::putline(std::string line) { int status; line += "\n"; status = send(fd_, line.c_str(), line.size(), MSG_NOSIGNAL); if (status != line.size()) { good_ = false; debug_with_errno(INFO, "Writing to socket"); } } void TCPSocket::receive_() { if (!good()) { return; } char rawbuf[RECVBUF + 1] = {0}; int status = 0; status = recv(fd_, rawbuf, RECVBUF, MSG_DONTWAIT | MSG_NOSIGNAL); if (status < 0 && errno == EAGAIN) { // Normal in non-blocking mode return; } if (status <= 0) { if (status != 0) { // 0 = Orderly shutdown connection debug_with_errno(INFO, "Socket read failed"); } good_ = false; return; } buf_ += std::string(rawbuf); if (buf_.length() > LINELENGTH && buf_.find('\n') == std::string::npos) { // Buffer grew too large // Disconnect to avoid denial of service attacks good_ = false; } }