From d81bc24155a29b8463af6eab0ef820ec1766ebac Mon Sep 17 00:00:00 2001 From: Thulinma Date: Mon, 27 Jan 2014 18:02:58 +0100 Subject: [PATCH] Implemented Util::Config::serveForkedSocket(), added Socket::Connection::drop() function for dropping unused sockets. --- lib/config.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++++++---- lib/config.h | 7 +++--- lib/socket.cpp | 44 +++++++++++++++++++++++++++++-------- lib/socket.h | 2 ++ 4 files changed, 95 insertions(+), 17 deletions(-) diff --git a/lib/config.cpp b/lib/config.cpp index 575fbbcb..23da5eff 100644 --- a/lib/config.cpp +++ b/lib/config.cpp @@ -5,6 +5,7 @@ #include "defines.h" #include "timing.h" #include "tinythread.h" +#include "stream.h" #include #include @@ -299,7 +300,7 @@ bool Util::Config::getBool(std::string optname){ struct callbackData{ Socket::Connection * sock; - void (*cb)(Socket::Connection &); + int (*cb)(Socket::Connection &); }; static void callThreadCallback(void * cDataArg){ @@ -312,8 +313,14 @@ static void callThreadCallback(void * cDataArg){ DEBUG_MSG(DLVL_INSANE, "Thread for %p ended", cDataArg); } -int Util::Config::serveThreadedSocket(void (*callback)(Socket::Connection &)){ - Socket::Server server_socket = Socket::Server(getInteger("listen_port"), getString("listen_interface"), false); +int Util::Config::serveThreadedSocket(int (*callback)(Socket::Connection &)){ + Socket::Server server_socket; + if (vals.isMember("socket")){ + server_socket = Socket::Server(Util::getTmpFolder() + getString("socket")); + } + if (vals.isMember("listen_port") && vals.isMember("listen_interface")){ + server_socket = Socket::Server(getInteger("listen_port"), getString("listen_interface"), false); + } if (!server_socket.connected()){return 1;} DEBUG_MSG(DLVL_DEVEL, "Activating threaded server: %s", getString("cmd").c_str()); activate(); @@ -337,6 +344,41 @@ int Util::Config::serveThreadedSocket(void (*callback)(Socket::Connection &)){ return 0; } +int Util::Config::serveForkedSocket(int (*callback)(Socket::Connection & S)){ + Socket::Server server_socket; + if (vals.isMember("socket")){ + server_socket = Socket::Server(Util::getTmpFolder() + getString("socket")); + } + if (vals.isMember("listen_port") && vals.isMember("listen_interface")){ + server_socket = Socket::Server(getInteger("listen_port"), getString("listen_interface"), false); + } + if (!server_socket.connected()){ + DEBUG_MSG(DLVL_DEVEL, "Failure to open socket"); + return 1; + } + DEBUG_MSG(DLVL_DEVEL, "Activating forked server: %s", getString("cmd").c_str()); + activate(); + + while (is_active && server_socket.connected()){ + Socket::Connection S = server_socket.accept(); + if (S.connected()){ //check if the new connection is valid + pid_t myid = fork(); + if (myid == 0){ //if new child, start MAINHANDLER + server_socket.drop(); + return callback(S); + }else{ //otherwise, do nothing or output debugging text + DEBUG_MSG(DLVL_DEVEL, "Forked new process %i for socket %i", (int)myid, S.getSocket()); + S.drop(); + } + }else{ + Util::sleep(10); //sleep 10ms + } + }//main loop + server_socket.close(); + DEBUG_MSG(DLVL_DEVEL, "Forked server exiting: %s", getString("cmd").c_str()); + return 0; +} + /// Activated the stored config. This will: /// - Drop permissions to the stored "username", if any. /// - Daemonize the process if "daemonize" exists and is true. @@ -425,7 +467,16 @@ void Util::Config::addBasicConnectorOptions(JSON::Value & capabilities){ capabilities["optional"]["username"]["help"] = "Username to drop privileges to - default if unprovided means do not drop privileges"; capabilities["optional"]["username"]["option"] = "--username"; capabilities["optional"]["username"]["type"] = "str"; - + + + if (capabilities.isMember("socket")){ + option.null(); + option["arg"] = "string"; + option["help"] = "Socket name that can be connected to for this connector."; + option["value"].append(capabilities["socket"]); + addOption("socket", option); + } + option.null(); option["long"] = "daemon"; option["short"] = "d"; diff --git a/lib/config.h b/lib/config.h index 001fcf8b..272f4ede 100644 --- a/lib/config.h +++ b/lib/config.h @@ -33,9 +33,9 @@ namespace Util { long long int getInteger(std::string optname); bool getBool(std::string optname); void activate(); - int serveThreadedSocket(void (*callback)(Socket::Connection & S)); - int serveForkedSocket(void (*callback)(Socket::Connection & S)); - int servePlainSocket(void (*callback)(Socket::Connection & S)); + int serveThreadedSocket(int (*callback)(Socket::Connection & S)); + int serveForkedSocket(int (*callback)(Socket::Connection & S)); + int servePlainSocket(int (*callback)(Socket::Connection & S)); void addBasicConnectorOptions(JSON::Value & capabilities); void addConnectorOptions(int port, JSON::Value & capabilities); }; @@ -53,4 +53,3 @@ namespace Util { void Daemonize(); } -; diff --git a/lib/socket.cpp b/lib/socket.cpp index 21ebeb90..11724f1b 100644 --- a/lib/socket.cpp +++ b/lib/socket.cpp @@ -238,11 +238,23 @@ bool Socket::Connection::isBlocking(){ /// Close connection. The internal socket is closed and then set to -1. /// If the connection is already closed, nothing happens. +/// This function calls shutdown, thus making the socket unusable in all other +/// processes as well. Do not use on shared sockets that are still in use. void Socket::Connection::close(){ + if (sock != -1){ + shutdown(sock, SHUT_RDWR); + } + drop(); +} //Socket::Connection::close + +/// Close connection. The internal socket is closed and then set to -1. +/// If the connection is already closed, nothing happens. +/// This function does *not* call shutdown, allowing continued use in other +/// processes. +void Socket::Connection::drop(){ if (connected()){ - DEBUG_MSG(DLVL_HIGH, "Socket %d closed", sock); if (sock != -1){ - shutdown(sock, SHUT_RDWR); + DEBUG_MSG(DLVL_HIGH, "Socket %d closed", sock); errno = EINTR; while (::close(sock) != 0 && errno == EINTR){ } @@ -261,7 +273,7 @@ void Socket::Connection::close(){ pipes[1] = -1; } } -} //Socket::Connection::close +} //Socket::Connection::drop /// Returns internal socket number. int Socket::Connection::getSocket(){ @@ -846,17 +858,31 @@ bool Socket::Server::isBlocking(){ /// Close connection. The internal socket is closed and then set to -1. /// If the connection is already closed, nothing happens. +/// This function calls shutdown, thus making the socket unusable in all other +/// processes as well. Do not use on shared sockets that are still in use. void Socket::Server::close(){ - if (connected()){ - DEBUG_MSG(DLVL_HIGH, "ServerSocket %d closed", sock); + if (sock != -1){ shutdown(sock, SHUT_RDWR); - errno = EINTR; - while (::close(sock) != 0 && errno == EINTR){ - } - sock = -1; } + drop(); } //Socket::Server::close +/// Close connection. The internal socket is closed and then set to -1. +/// If the connection is already closed, nothing happens. +/// This function does *not* call shutdown, allowing continued use in other +/// processes. +void Socket::Server::drop(){ + if (connected()){ + if (sock != -1){ + DEBUG_MSG(DLVL_HIGH, "ServerSocket %d closed", sock); + errno = EINTR; + while (::close(sock) != 0 && errno == EINTR){ + } + sock = -1; + } + } +} //Socket::Server::drop + /// Returns the connected-state for this socket. /// Note that this function might be slightly behind the real situation. /// The connection status is updated after every accept attempt, when errors occur diff --git a/lib/socket.h b/lib/socket.h index 75160bd5..3b9d5db7 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -68,6 +68,7 @@ namespace Socket { Connection(int write, int read); ///< Simulate a socket using two file descriptors. //generic methods void close(); ///< Close connection. + void drop(); ///< Close connection without shutdown. void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false). bool isBlocking(); ///< Check if this socket is blocking (true) or nonblocking (false). std::string getHost(); ///< Gets hostname for connection, if available. @@ -114,6 +115,7 @@ namespace Socket { bool connected() const; ///< Returns the connected-state for this socket. bool isBlocking(); ///< Check if this socket is blocking (true) or nonblocking (false). void close(); ///< Close connection. + void drop(); ///< Close connection without shutdown. int getSocket(); ///< Returns internal socket number. };