diff options
Diffstat (limited to 'src/socket/ingen_socket_server.cpp')
-rw-r--r-- | src/socket/ingen_socket_server.cpp | 118 |
1 files changed, 110 insertions, 8 deletions
diff --git a/src/socket/ingen_socket_server.cpp b/src/socket/ingen_socket_server.cpp index 37b05bae..0a9d7494 100644 --- a/src/socket/ingen_socket_server.cpp +++ b/src/socket/ingen_socket_server.cpp @@ -14,31 +14,133 @@ along with Ingen. If not, see <http://www.gnu.org/licenses/>. */ +#include <errno.h> +#include <poll.h> + +#include <sstream> +#include <thread> + +#include "ingen/Configuration.hpp" #include "ingen/Module.hpp" #include "ingen/World.hpp" #include "../server/Engine.hpp" #include "../server/EventWriter.hpp" -#include "SocketListener.hpp" +#include "Socket.hpp" +#include "SocketServer.hpp" + +#define UNIX_SCHEME "unix://" + +namespace Ingen { +namespace Socket { + +static void +ingen_listen(Ingen::World* world, Socket* unix_sock, Socket* net_sock) +{ + const std::string unix_path(world->conf().option("socket").ptr<char>()); + + SPtr<Server::Engine> engine = dynamic_ptr_cast<Server::Engine>( + world->engine()); + + // Bind UNIX socket + const Raul::URI unix_uri(UNIX_SCHEME + unix_path); + if (!unix_sock->bind(unix_uri) || !unix_sock->listen()) { + world->log().error("Failed to create UNIX socket\n"); + unix_sock->close(); + } + world->log().info(Raul::fmt("Listening on socket %1%\n") % unix_uri); -using namespace Ingen; + // Bind TCP socket + const int port = world->conf().option("engine-port").get<int32_t>(); + std::ostringstream ss; + ss << "tcp://localhost:"; + ss << port; + if (!net_sock->bind(Raul::URI(ss.str())) || !net_sock->listen()) { + world->log().error("Failed to create TCP socket\n"); + net_sock->close(); + } + world->log().info(Raul::fmt("Listening on TCP port %1%\n") % port); -struct IngenSocketServerModule : public Ingen::Module { - void load(Ingen::World* world) { - listener = SPtr<Ingen::Socket::SocketListener>( - new Ingen::Socket::SocketListener(*world)); + struct pollfd pfds[2]; + int nfds = 0; + if (unix_sock->fd() != -1) { + pfds[nfds].fd = unix_sock->fd(); + pfds[nfds].events = POLLIN; + pfds[nfds].revents = 0; + ++nfds; + } + if (net_sock->fd() != -1) { + pfds[nfds].fd = net_sock->fd(); + pfds[nfds].events = POLLIN; + pfds[nfds].revents = 0; + ++nfds; } - SPtr<Ingen::Socket::SocketListener> listener; + while (true) { + // Wait for input to arrive at a socket + const int ret = poll(pfds, nfds, -1); + if (ret == -1) { + world->log().error(Raul::fmt("Poll error: %1%\n") % strerror(errno)); + break; + } else if ((pfds[0].revents & POLLHUP) || pfds[1].revents & POLLHUP) { + break; + } else if (ret == 0) { + world->log().error("Poll returned with no data\n"); + continue; + } + + if (pfds[0].revents & POLLIN) { + SPtr<Socket> conn = unix_sock->accept(); + if (conn) { + new SocketServer(*world, *engine, conn); + } + } + + if (pfds[1].revents & POLLIN) { + SPtr<Socket> conn = net_sock->accept(); + if (conn) { + new SocketServer(*world, *engine, conn); + } + } + } +} + +struct ServerModule : public Ingen::Module +{ + ServerModule() + : unix_sock(Socket::Type::UNIX) + , net_sock(Socket::Type::TCP) + {} + + ~ServerModule() { + unix_sock.shutdown(); + net_sock.shutdown(); + thread->join(); + unlink(unix_sock.uri().substr(strlen(UNIX_SCHEME)).c_str()); + } + + void load(World* world) { + world = world; + thread = std::unique_ptr<std::thread>( + new std::thread(ingen_listen, world, &unix_sock, &net_sock)); + } + + World* world; + Socket unix_sock; + Socket net_sock; + std::unique_ptr<std::thread> thread; }; +} // namespace Socket +} // namespace Ingen + extern "C" { Ingen::Module* ingen_module_load() { - return new IngenSocketServerModule(); + return new Ingen::Socket::ServerModule(); } } // extern "C" |