/* * extendes sockets */ #include #include #include "sock.h" #include "helpers.h" static int clientno = 0; /* * cVdrmonSocket */ cVdrmanagerSocket::cVdrmanagerSocket() { sock = -1; } cVdrmanagerSocket::~cVdrmanagerSocket() { Close(); } void cVdrmanagerSocket::Close() { if (socket >= 0) { close(sock); sock = -1; } } int cVdrmanagerSocket::GetSocket() { return sock; } bool cVdrmanagerSocket::MakeDontBlock() { // make it non-blocking: int oldflags = fcntl(sock, F_GETFL, 0); if (oldflags < 0) { LOG_ERROR; return false; } oldflags |= O_NONBLOCK; if (fcntl(sock, F_SETFL, oldflags) < 0) { LOG_ERROR; return false; } return true; } const char * cVdrmanagerSocket::GetPassword() { return password; } /* * cVdrmonServerSocket */ cVdrmanagerServerSocket::cVdrmanagerServerSocket() : cVdrmanagerSocket() { } cVdrmanagerServerSocket::~cVdrmanagerServerSocket() { } bool cVdrmanagerServerSocket::Create(int port, const char * password, bool forceCheckSvrp) { // save password this->password = password; this->forceCheckSvdrp = forceCheckSvrp; // create socket sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) { LOG_ERROR; return false; } // allow it to always reuse the same port: int ReUseAddr = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ReUseAddr, sizeof(ReUseAddr)); // bind to address struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = htons(port); name.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) { LOG_ERROR; Close(); return false; } // make it non-blocking: if (!MakeDontBlock()) { Close(); return false; } // listen to the socket: if (listen(sock, 100) < 0) { LOG_ERROR; Close(); return false; } return true; } cVdrmanagerClientSocket * cVdrmanagerServerSocket::Accept() { cVdrmanagerClientSocket * newsocket = NULL; // accept the connection struct sockaddr_in clientname; uint size = sizeof(clientname); int newsock = accept(sock, (struct sockaddr *) &clientname, &size); if (newsock > 0) { // create client socket newsocket = new cVdrmanagerClientSocket(password); if (!newsocket->Attach(newsock)) { delete newsocket; return NULL; } if (!IsPasswordSet() || forceCheckSvdrp == true) { bool accepted = SVDRPhosts.Acceptable(clientname.sin_addr.s_addr); if (!accepted) { newsocket->PutLine(string("NACC Access denied.\n")); newsocket->Flush(); delete newsocket; newsocket = NULL; } dsyslog( "[vdrmon] connect from %s, port %hd - %s", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), accepted ? "accepted" : "DENIED"); } } else if (errno != EINTR && errno != EAGAIN ) LOG_ERROR; return newsocket; } /* * cVdrmonClientSocket */ cVdrmanagerClientSocket::cVdrmanagerClientSocket(const char * password) { readbuf = writebuf = ""; disconnected = false; client = ++clientno; this->password = password; login = false; } cVdrmanagerClientSocket::~cVdrmanagerClientSocket() { } bool cVdrmanagerClientSocket::IsLineComplete() { // check a for complete line string::size_type pos = readbuf.find("\r", 0); if (pos == string::npos) pos = readbuf.find("\n"); return pos != string::npos; } bool cVdrmanagerSocket::IsPasswordSet(){ return strcmp(password, ""); } bool cVdrmanagerClientSocket::GetLine(string& line) { // check the line string::size_type pos = readbuf.find("\r", 0); if (pos == string::npos) pos = readbuf.find("\n", 0); if (pos == string::npos) return false; // extract the line ... line = readbuf.substr(0, pos); // handle \r\n if (readbuf[pos] == '\r' && readbuf.length() > pos && readbuf[pos + 1] == '\n') pos++; // ... and move the remainder readbuf = readbuf.substr(pos + 1); return true; } bool cVdrmanagerClientSocket::Read() { if (Disconnected()) return false; int rc; bool len = 0; char buf[2001]; while ((rc = read(sock, buf, sizeof(buf) - 1)) > 0) { buf[rc] = 0; readbuf += buf; len += rc; } if (rc < 0 && errno != EAGAIN) { LOG_ERROR; return false; } else if (rc == 0) { disconnected = true; } return len > 0; } bool cVdrmanagerClientSocket::Disconnected() { return disconnected; } void cVdrmanagerClientSocket::Disconnect() { disconnected = true; } bool cVdrmanagerClientSocket::PutLine(string line) { //TODO http://projects.vdr-developer.org/issues/790 string line2 = cHelpers::compress_string(line); isyslog("PutLine, line size is %s, with zlib it would be %s", line.size(), line2.size()); // add line to write buffer writebuf += line; // data present? if (writebuf.length() > 0) { // write so many bytes as possible int rc = write(sock, writebuf.c_str(), writebuf.length()); if (rc < 0 && errno != EAGAIN) { LOG_ERROR; return false; } // move the remainder if (rc > 0) writebuf = writebuf.substr(rc, writebuf.length() - rc); } return true; } bool cVdrmanagerClientSocket::Flush() { string empty = ""; return PutLine(empty); } bool cVdrmanagerClientSocket::Attach(int fd) { sock = fd; return MakeDontBlock(); } int cVdrmanagerClientSocket::GetClientId() { return client; } bool cVdrmanagerClientSocket::WritePending() { return writebuf.length() > 0; } bool cVdrmanagerClientSocket::IsLoggedIn() { return login || !password || !*password; } void cVdrmanagerClientSocket::SetLoggedIn() { login = true; }