/* This file is part of Ingen. Copyright 2007-2012 David Robillard Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. Ingen is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. You should have received a copy of the GNU Affero General Public License along with Ingen. If not, see . */ #include #include #include #include #include "ingen/Interface.hpp" #include "ingen/shared/World.hpp" #include "ingen/shared/AtomReader.hpp" #include "sord/sordmm.hpp" #include "sratom/sratom.h" #include "SocketInterface.hpp" #include "../server/Event.hpp" #include "../server/PostProcessor.hpp" #include "../server/ThreadManager.hpp" #define LOG(s) s << "[SocketInterface] " namespace Ingen { namespace Socket { SocketInterface::SocketInterface(Ingen::Shared::World& world, int conn) : _world(world) , _iface(*(Server::Engine*)world.local_engine().get(), *this) , _event(NULL) , _conn(conn) { // Set connection to non-blocking so parser can read until EOF // and not block indefinitely waiting for more input fcntl(_conn, F_SETFL, fcntl(_conn, F_GETFL, 0) | O_NONBLOCK); set_name("SocketInterface"); start(); } SocketInterface::~SocketInterface() { stop(); join(); close(_conn); } void SocketInterface::event(Server::Event* ev) { assert(!_event); ev->pre_process(); _event = ev; } bool SocketInterface::process(Server::PostProcessor& dest, Server::ProcessContext& context, bool limit) { if (_event) { _event->execute(context); dest.append(_event, _event); _event = NULL; } if (_conn == -1) { return false; } return true; } void SocketInterface::_run() { Thread::set_context(Server::THREAD_PRE_PROCESS); while (!_exit_flag) { // Set up a reader to parse the Turtle message into a model Sord::World* world = _world.rdf_world(); SerdEnv* env = world->prefixes().c_obj(); SordModel* model = sord_new(world->c_obj(), SORD_SPO, false); SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL); // Set base URI to path: so e.g. will be a path SordNode* base_uri = sord_new_uri( world->c_obj(), (const uint8_t*)"path:"); serd_env_set_base_uri(env, sord_node_to_serd_node(base_uri)); LV2_URID_Map* map = &_world.lv2_uri_map()->urid_map_feature()->urid_map; // Set up sratom to build an LV2_Atom from the model Sratom* sratom = sratom_new(map); SerdChunk chunk = { NULL, 0 }; LV2_Atom_Forge forge; lv2_atom_forge_init(&forge, map); lv2_atom_forge_set_sink( &forge, sratom_forge_sink, sratom_forge_deref, &chunk); // Read directly from the connection with serd FILE* f = fdopen(_conn, "r"); if (!f) { LOG(Raul::error) << "Failed to open connection " << _conn << "(" << strerror(errno) << ")" << std::endl; // Connection gone, exit break; } serd_reader_read_file_handle(reader, f, (const uint8_t*)"(socket)"); // FIXME: Sratom needs work to be able to read resources SordNode* msg_node = sord_new_blank( world->c_obj(), (const uint8_t*)"genid1"); // Build an LV2_Atom at chunk.buf from the message sratom_read(sratom, &forge, world->c_obj(), model, msg_node); // Make an AtomReader to read that atom and do Ingen things Shared::AtomReader ar(*_world.lv2_uri_map().get(), *_world.uris().get(), _world.forge(), _iface); // Call _iface methods based on atom content ar.write((LV2_Atom*)chunk.buf); // Respond and close connection write(_conn, "OK", 2); fclose(f); sratom_free(sratom); sord_node_free(world->c_obj(), msg_node); serd_reader_free(reader); sord_free(model); } _conn = -1; } } // namespace Ingen } // namespace Socket