diff options
Diffstat (limited to 'vdr-vdrmanager/serversock.cpp')
-rw-r--r-- | vdr-vdrmanager/serversock.cpp | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/vdr-vdrmanager/serversock.cpp b/vdr-vdrmanager/serversock.cpp new file mode 100644 index 0000000..927a788 --- /dev/null +++ b/vdr-vdrmanager/serversock.cpp @@ -0,0 +1,148 @@ +/* + * extendes sockets + */ +#include <unistd.h> +#include <vdr/plugin.h> +#include <openssl/err.h> +#include "serversock.h" +#include "helpers.h" +#include "compressor.h" + +static int clientno = 0; + +/* + * cVdrmonServerSocket + */ +cVdrmanagerServerSocket::cVdrmanagerServerSocket() : cVdrmanagerSocket() { + port = -1; + sslCtx = NULL; +} + +cVdrmanagerServerSocket::~cVdrmanagerServerSocket() { + if (sslCtx) + SSL_CTX_free(sslCtx); +} + +bool cVdrmanagerServerSocket::Create(int port, const char * password, bool forceCheckSvrp, int compressionMode, + const char * certFile, const char * keyFile) { + + this->port = port; + this->password = password; + this->forceCheckSvdrp = forceCheckSvrp; + this->compressionMode = compressionMode; + + // create socket + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock < 0) { + LOG_ERROR; + return false; + } + + isyslog("[vdrmanager] created %sSSL server socket on port %d", certFile ? "" : "non ", port); + + // 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; + } + + if (certFile) { + isyslog("[vdrmanager] initialize SSL"); + + OpenSSL_add_all_algorithms(); + OpenSSL_add_all_ciphers(); + OpenSSL_add_all_digests(); + OpenSSL_add_ssl_algorithms(); + + SSL_load_error_strings(); + SSL_library_init(); + + const SSL_METHOD * method = SSLv23_server_method(); + sslCtx = SSL_CTX_new(method); + if (sslCtx == NULL) { + long errorCode = ERR_get_error(); + char * error = ERR_error_string(errorCode, NULL); + esyslog("[vdrmanager] Error initializing SSL context: %s", error); + Close(); + return false; + } + + /* set the local certificate from CertFile */ + SSL_CTX_use_certificate_file(sslCtx, certFile, SSL_FILETYPE_PEM); + /* set the private key from KeyFile */ + SSL_CTX_use_PrivateKey_file(sslCtx, keyFile, SSL_FILETYPE_PEM); + /* verify private key */ + if (!SSL_CTX_check_private_key(sslCtx)) { + long errorCode = ERR_get_error(); + char * error = ERR_error_string(errorCode, NULL); + esyslog("[vdrmanager] Error checking SSL keys: %s", error); + Close(); + return false; + } + + SSL_CTX_set_mode(sslCtx, SSL_MODE_ENABLE_PARTIAL_WRITE); + } + + return true; +} + +cVdrmanagerClientSocket * cVdrmanagerServerSocket::Accept() { + cVdrmanagerClientSocket * newsocket = NULL; + + isyslog("[vdrmanager] new %sclient on port %d", sslCtx ? "SSL " : "", port); + + // 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, compressionMode); + if (!newsocket->Attach(newsock, sslCtx)) { + delete newsocket; + return NULL; + } + + if (!IsPasswordSet() || forceCheckSvdrp == true) { + bool accepted = SVDRPhosts.Acceptable(clientname.sin_addr.s_addr); + if (!accepted) { + newsocket->Write(string("NACC Access denied.\n")); + newsocket->Flush(); + delete newsocket; + newsocket = NULL; + } + dsyslog( + "[vdrmanager] 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; +} + +int cVdrmanagerServerSocket::GetPort() { + return port; +} |