diff options
Diffstat (limited to 'vdr-vdrmanager/sock.cpp')
-rw-r--r-- | vdr-vdrmanager/sock.cpp | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/vdr-vdrmanager/sock.cpp b/vdr-vdrmanager/sock.cpp new file mode 100644 index 0000000..80b03b2 --- /dev/null +++ b/vdr-vdrmanager/sock.cpp @@ -0,0 +1,286 @@ +/* + * extendes sockets + */ +#include <unistd.h> +#include <vdr/plugin.h> +#include "sock.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) +{ + // save password + this->password = password; + + // 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; + } + + 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 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) +{ + // 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; +} |