summaryrefslogtreecommitdiffstats
path: root/src/socket
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-05-10 02:14:55 +0000
committerDavid Robillard <d@drobilla.net>2012-05-10 02:14:55 +0000
commit281bbcc6a7208c28283bc9bdd521c5d6cc48a60f (patch)
tree6cfc2bf6c3c0d92b3cb5a79a4d019d5952d41989 /src/socket
parentcd2ac251d7e076e3bf25f2640d1684447efa83d3 (diff)
downloadingen-281bbcc6a7208c28283bc9bdd521c5d6cc48a60f.tar.gz
ingen-281bbcc6a7208c28283bc9bdd521c5d6cc48a60f.tar.bz2
ingen-281bbcc6a7208c28283bc9bdd521c5d6cc48a60f.zip
Bidirectional socket communication (GUI once again works remotely).
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4335 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/socket')
-rw-r--r--src/socket/Socket.cpp132
-rw-r--r--src/socket/Socket.hpp62
-rw-r--r--src/socket/SocketClient.hpp52
-rw-r--r--src/socket/SocketListener.cpp22
-rw-r--r--src/socket/SocketReader.cpp18
-rw-r--r--src/socket/SocketReader.hpp25
-rw-r--r--src/socket/SocketServer.hpp53
-rw-r--r--src/socket/SocketWriter.cpp74
-rw-r--r--src/socket/SocketWriter.hpp65
-rw-r--r--src/socket/ingen_socket_client.cpp57
-rw-r--r--src/socket/wscript18
11 files changed, 494 insertions, 84 deletions
diff --git a/src/socket/Socket.cpp b/src/socket/Socket.cpp
index 7fb4d89b..daeb6fa2 100644
--- a/src/socket/Socket.cpp
+++ b/src/socket/Socket.cpp
@@ -15,11 +15,12 @@
*/
#include <errno.h>
+#include <netdb.h>
#include <netinet/in.h>
#include <poll.h>
+#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <stdlib.h>
#include <string>
#include <sstream>
@@ -33,51 +34,104 @@
namespace Ingen {
namespace Socket {
-bool
-Socket::open_unix(const std::string& uri, const std::string& path)
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
+Socket::Socket(Type t)
+ : _type(t)
+ , _addr(NULL)
+ , _addr_len(0)
+ , _sock(-1)
{
- if ((_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
- return false;
+ switch (t) {
+ case UNIX:
+ _sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ break;
+ case TCP:
+ _sock = socket(AF_INET, SOCK_STREAM, 0);
+ break;
}
+}
- struct sockaddr_un* uaddr = (struct sockaddr_un*)calloc(
- 1, sizeof(struct sockaddr_un));
- uaddr->sun_family = AF_UNIX;
- strncpy(uaddr->sun_path, path.c_str(), sizeof(uaddr->sun_path) - 1);
- _uri = uri;
- _addr = (sockaddr*)uaddr;
- _addr_len = sizeof(struct sockaddr_un);
-
- return bind();
+Socket::Socket(Type t,
+ const std::string& uri,
+ struct sockaddr* addr,
+ socklen_t addr_len,
+ int fd)
+ : _type(t)
+ , _uri(uri)
+ , _addr(addr)
+ , _addr_len(addr_len)
+ , _sock(fd)
+{
}
bool
-Socket::open_tcp(const std::string& uri, uint16_t port)
+Socket::set_addr(const std::string& uri)
{
- if ((_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- return false;
+ if (_type == UNIX && uri.substr(0, strlen("unix://")) == "unix://") {
+ const std::string path = uri.substr(strlen("unix://"));
+ struct sockaddr_un* uaddr = (struct sockaddr_un*)calloc(
+ 1, sizeof(struct sockaddr_un));
+ uaddr->sun_family = AF_UNIX;
+ strncpy(uaddr->sun_path, path.c_str(), sizeof(uaddr->sun_path) - 1);
+ _uri = uri;
+ _addr = (sockaddr*)uaddr;
+ _addr_len = sizeof(struct sockaddr_un);
+ return true;
+ } else if (_type == TCP && uri.find("://") != std::string::npos) {
+ const std::string no_scheme = uri.substr(uri.find("://") + 4);
+ const size_t port_sep = no_scheme.find(':');
+ if (port_sep == std::string::npos) {
+ return false;
+ }
+
+ const std::string host = no_scheme.substr(0, port_sep);
+ const std::string port = no_scheme.substr(port_sep + 1).c_str();
+
+ struct addrinfo* ainfo;
+ int st = 0;
+ if ((st = getaddrinfo(host.c_str(), port.c_str(), NULL, &ainfo))) {
+ LOG(Raul::error) << "Error in getaddrinfo: "
+ << gai_strerror(st) << std::endl;
+ return false;
+ }
+
+ _uri = uri;
+ _addr = (struct sockaddr*)malloc(ainfo->ai_addrlen);
+ _addr_len = ainfo->ai_addrlen;
+ memcpy(_addr, ainfo->ai_addr, ainfo->ai_addrlen);
+ return true;
}
+ return false;
+}
- struct sockaddr_in* naddr = (struct sockaddr_in*)calloc(
- 1, sizeof(struct sockaddr_in));
- naddr->sin_family = AF_INET;
- naddr->sin_port = htons(port);
- _uri = uri;
- _addr = (sockaddr*)naddr;
- _addr_len = sizeof(struct sockaddr_in);
-
- return bind();
+bool
+Socket::bind(const std::string& uri)
+{
+ if (set_addr(uri) && ::bind(_sock, _addr, _addr_len) != -1) {
+ return true;
+ }
+
+ LOG(Raul::error) << "Failed to bind " << _uri
+ << ": " << strerror(errno) << std::endl;
+ return false;
}
bool
-Socket::bind()
+Socket::connect(const std::string& uri)
{
- if (::bind(_sock, _addr, _addr_len) == -1) {
- LOG(Raul::error) << "Failed to bind " << _uri
- << ": " << strerror(errno) << std::endl;
- return false;
+ if (set_addr(uri) && ::connect(_sock, _addr, _addr_len) != -1) {
+ return true;
}
- return true;
+
+ LOG(Raul::error) << "Failed to connect " << _uri
+ << ": " << strerror(errno) << std::endl;
+ return false;
}
bool
@@ -92,10 +146,9 @@ Socket::listen()
}
}
-int
+SharedPtr<Socket>
Socket::accept()
{
- // Accept connection from client
socklen_t client_addr_len = _addr_len;
struct sockaddr* client_addr = (struct sockaddr*)calloc(
1, client_addr_len);
@@ -104,9 +157,18 @@ Socket::accept()
if (conn == -1) {
LOG(Raul::error) << "Error accepting connection: "
<< strerror(errno) << std::endl;
+ return SharedPtr<Socket>();
}
- return conn;
+ std::string client_uri = _uri;
+ char host[NI_MAXHOST];
+ if (getnameinfo(client_addr, client_addr_len,
+ host, sizeof(host), NULL, 0, 0)) {
+ client_uri = _uri.substr(0, _uri.find(":") + 1) + host;
+ }
+
+ return SharedPtr<Socket>(
+ new Socket(_type, client_uri, client_addr, client_addr_len, conn));
}
void
diff --git a/src/socket/Socket.hpp b/src/socket/Socket.hpp
index fa2b6972..dd62aefa 100644
--- a/src/socket/Socket.hpp
+++ b/src/socket/Socket.hpp
@@ -14,32 +14,59 @@
along with Ingen. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifndef INGEN_SOCKET_SOCKET_HPP
+#define INGEN_SOCKET_SOCKET_HPP
+
#include <stdint.h>
#include <sys/socket.h>
#include <string>
+#include "raul/SharedPtr.hpp"
+#include "raul/Noncopyable.hpp"
+
namespace Ingen {
namespace Socket {
-class Socket {
+/** A safe and simple interface for UNIX or TCP sockets. */
+class Socket : public Raul::Noncopyable {
public:
- Socket() : _addr(NULL), _addr_len(0), _sock(-1) {}
+ enum Type {
+ UNIX,
+ TCP
+ };
+
+ static Type type_from_uri(const std::string& uri) {
+ if (uri.substr(0, strlen("unix://")) == "unix://") {
+ return UNIX;
+ } else {
+ return TCP;
+ }
+ }
+
+ /** Create a new unbound/unconnected socket of a given type. */
+ Socket(Type t);
+
+ /** Wrap an existing open socket. */
+ Socket(Type t,
+ const std::string& uri,
+ struct sockaddr* addr,
+ socklen_t addr_len,
+ int fd);
+
~Socket() { close(); }
- /** Open UNIX socket and bind to address.
- * @param uri URI used for identification and log output.
- * @param path Socket path.
- * @return True on success
+ /** Bind a server socket to an address.
+ * @param uri Address URI, e.g. unix:///tmp/foo or tcp://somehost:1234
+ * @return True on success.
*/
- bool open_unix(const std::string& uri, const std::string& path);
+ bool bind(const std::string& uri);
- /** Open TCP socket and bind to address.
- * @param uri URI used for identification and log output.
- * @param port Port number.
- * @return True on success
+ /** Connect a client socket to a server address.
+ * @param uri Address URI, e.g. unix:///tmp/foo or tcp://somehost:1234
+ * @return True on success.
*/
- bool open_tcp(const std::string& uri, uint16_t port);
+ bool connect(const std::string& uri);
/** Mark server socket as passive to listen for incoming connections.
* @return True on success.
@@ -47,19 +74,22 @@ public:
bool listen();
/** Accept a connection.
- * @return The socket file descriptor, or -1 on error.
+ * @return An new open socket for the connection.
*/
- int accept();
+ SharedPtr<Socket> accept();
/** Return the file descriptor for the socket. */
int fd() { return _sock; }
+ const std::string& uri() const { return _uri; }
+
/** Close the socket. */
void close();
private:
- bool bind();
+ bool set_addr(const std::string& uri);
+ Type _type;
std::string _uri;
struct sockaddr* _addr;
socklen_t _addr_len;
@@ -68,3 +98,5 @@ private:
} // namespace Socket
} // namespace Ingen
+
+#endif // INGEN_SOCKET_SOCKET_HPP
diff --git a/src/socket/SocketClient.hpp b/src/socket/SocketClient.hpp
new file mode 100644
index 00000000..22e6eeb4
--- /dev/null
+++ b/src/socket/SocketClient.hpp
@@ -0,0 +1,52 @@
+/*
+ This file is part of Ingen.
+ Copyright 2012 David Robillard <http://drobilla.net/>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_SOCKET_SOCKET_CLIENT_HPP
+#define INGEN_SOCKET_SOCKET_CLIENT_HPP
+
+#include "SocketReader.hpp"
+#include "SocketWriter.hpp"
+
+namespace Ingen {
+namespace Socket {
+
+/** The client side of an Ingen socket connection. */
+class SocketClient : public SocketWriter
+{
+public:
+ SocketClient(Shared::World& world,
+ const std::string& uri,
+ SharedPtr<Socket> sock,
+ SharedPtr<Interface> respondee)
+ : SocketWriter(*world.lv2_uri_map().get(),
+ *world.uris().get(),
+ uri,
+ sock)
+ , _respondee(respondee)
+ , _reader(world, *respondee.get(), sock)
+ {
+ _reader.start();
+ }
+
+private:
+ SharedPtr<Interface> _respondee;
+ SocketReader _reader;
+};
+
+} // namespace Socket
+} // namespace Ingen
+
+#endif // INGEN_SOCKET_SOCKET_CLIENT_HPP
diff --git a/src/socket/SocketListener.cpp b/src/socket/SocketListener.cpp
index 6f41383b..fa58ff44 100644
--- a/src/socket/SocketListener.cpp
+++ b/src/socket/SocketListener.cpp
@@ -29,7 +29,7 @@
#include "../server/Engine.hpp"
#include "../server/EventWriter.hpp"
#include "SocketListener.hpp"
-#include "SocketReader.hpp"
+#include "SocketServer.hpp"
#define LOG(s) s << "[SocketListener] "
@@ -38,13 +38,15 @@ namespace Socket {
SocketListener::SocketListener(Ingen::Shared::World& world)
: _world(world)
+ , _unix_sock(Socket::UNIX)
+ , _net_sock(Socket::TCP)
{
set_name("SocketListener");
// Create UNIX socket
_unix_path = world.conf()->option("socket").get_string();
const std::string unix_uri = "unix://" + _unix_path;
- if (!_unix_sock.open_unix(unix_uri, _unix_path) || !_unix_sock.listen()) {
+ if (!_unix_sock.bind(unix_uri) || !_unix_sock.listen()) {
LOG(Raul::error) << "Failed to create UNIX socket" << std::endl;
_unix_sock.close();
}
@@ -54,7 +56,7 @@ SocketListener::SocketListener(Ingen::Shared::World& world)
std::ostringstream ss;
ss << "tcp:///localhost:";
ss << port;
- if (!_net_sock.open_tcp(ss.str(), port) || !_net_sock.listen()) {
+ if (!_net_sock.bind(ss.str()) || !_net_sock.listen()) {
LOG(Raul::error) << "Failed to create TCP socket" << std::endl;
_net_sock.close();
}
@@ -103,18 +105,16 @@ SocketListener::_run()
}
if (pfds[0].revents & POLLIN) {
- int conn = _unix_sock.accept();
- if (conn != -1) {
- // Make an new interface/thread to handle the connection
- new SocketReader(_world, *engine->interface(), conn);
+ SharedPtr<Socket> conn = _unix_sock.accept();
+ if (conn) {
+ new SocketServer(_world, *engine, conn);
}
}
if (pfds[1].revents & POLLIN) {
- int conn = _net_sock.accept();
- if (conn != -1) {
- // Make an new interface/thread to handle the connection
- new SocketReader(_world, *engine->interface(), conn);
+ SharedPtr<Socket> conn = _net_sock.accept();
+ if (conn) {
+ new SocketServer(_world, *engine, conn);
}
}
}
diff --git a/src/socket/SocketReader.cpp b/src/socket/SocketReader.cpp
index 2d1b5c14..74d441ef 100644
--- a/src/socket/SocketReader.cpp
+++ b/src/socket/SocketReader.cpp
@@ -31,12 +31,12 @@ namespace Socket {
SocketReader::SocketReader(Ingen::Shared::World& world,
Interface& iface,
- int conn)
+ SharedPtr<Socket> sock)
: _world(world)
, _iface(iface)
, _inserter(NULL)
, _msg_node(NULL)
- , _conn(conn)
+ , _socket(sock)
{
set_name("SocketReader");
start();
@@ -46,7 +46,6 @@ SocketReader::~SocketReader()
{
stop();
join();
- close(_conn);
}
SerdStatus
@@ -119,12 +118,12 @@ SocketReader::_run()
serd_env_set_base_uri(_env, sord_node_to_serd_node(base_uri));
// Read directly from the connection with serd
- FILE* f = fdopen(_conn, "r");
+ FILE* f = fdopen(_socket->fd(), "r");
if (!f) {
- LOG(Raul::error) << "Failed to open connection " << _conn
+ LOG(Raul::error) << "Failed to open connection "
<< "(" << strerror(errno) << ")" << std::endl;
// Connection gone, exit
- _conn = -1;
+ _socket.reset();
return;
}
@@ -137,7 +136,7 @@ SocketReader::_run()
_iface);
struct pollfd pfd;
- pfd.fd = _conn;
+ pfd.fd = _socket->fd();
pfd.events = POLLIN;
pfd.revents = 0;
@@ -159,7 +158,7 @@ SocketReader::_run()
if (st == SERD_FAILURE) {
continue; // Read nothing, e.g. just whitespace
} else if (st) {
- fprintf(stderr, "Read error: %s\n", serd_strerror(st));
+ LOG(Raul::error) << "Read error: " << serd_strerror(st) << std::endl;
continue;
} else if (!_msg_node) {
LOG(Raul::error) << "Received empty message" << std::endl;
@@ -172,9 +171,6 @@ SocketReader::_run()
// Call _iface methods based on atom content
ar.write((LV2_Atom*)chunk.buf);
- // Respond and close connection
- write(_conn, "OK", 2);
-
// Reset everything for the next iteration
chunk.len = 0;
sord_node_free(world->c_obj(), _msg_node);
diff --git a/src/socket/SocketReader.hpp b/src/socket/SocketReader.hpp
index 141e6216..5e205186 100644
--- a/src/socket/SocketReader.hpp
+++ b/src/socket/SocketReader.hpp
@@ -20,19 +20,24 @@
#include "raul/Thread.hpp"
#include "sord/sord.h"
+#include "Socket.hpp"
+
namespace Ingen {
-namespace Shared {
-class World;
class Interface;
-}
+
+namespace Shared { class World; }
namespace Socket {
+/** Calls Interface methods based on Turtle messages received via socket. */
class SocketReader : public Raul::Thread
{
public:
- SocketReader(Shared::World& world, Interface& iface, int conn);
+ SocketReader(Shared::World& world,
+ Interface& iface,
+ SharedPtr<Socket> sock);
+
~SocketReader();
private:
@@ -54,12 +59,12 @@ private:
const SerdNode* object_datatype,
const SerdNode* object_lang);
- Shared::World& _world;
- Interface& _iface;
- SerdEnv* _env;
- SordInserter* _inserter;
- SordNode* _msg_node;
- int _conn;
+ Shared::World& _world;
+ Interface& _iface;
+ SerdEnv* _env;
+ SordInserter* _inserter;
+ SordNode* _msg_node;
+ SharedPtr<Socket> _socket;
};
} // namespace Ingen
diff --git a/src/socket/SocketServer.hpp b/src/socket/SocketServer.hpp
new file mode 100644
index 00000000..8ea0f445
--- /dev/null
+++ b/src/socket/SocketServer.hpp
@@ -0,0 +1,53 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2012 David Robillard <http://drobilla.net/>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_SOCKET_SOCKET_SERVER_HPP
+#define INGEN_SOCKET_SOCKET_SERVER_HPP
+
+#include "../server/EventWriter.hpp"
+#include "Socket.hpp"
+#include "SocketReader.hpp"
+#include "SocketWriter.hpp"
+
+namespace Ingen {
+namespace Socket {
+
+/** The server side of an Ingen socket connection. */
+class SocketServer : public Server::EventWriter, public SocketReader
+{
+public:
+ SocketServer(Shared::World& world,
+ Server::Engine& engine,
+ SharedPtr<Socket> sock)
+ : Server::EventWriter(engine)
+ , SocketReader(world, *this, sock)
+ , _writer(*world.lv2_uri_map().get(),
+ *world.uris().get(),
+ sock->uri(),
+ sock)
+ {
+ set_respondee(&_writer);
+ engine.register_client(sock->uri(), &_writer);
+ }
+
+private:
+ SocketWriter _writer;
+};
+
+} // namespace Ingen
+} // namespace Socket
+
+#endif // INGEN_SOCKET_SOCKET_SERVER_HPP
diff --git a/src/socket/SocketWriter.cpp b/src/socket/SocketWriter.cpp
new file mode 100644
index 00000000..29bc018b
--- /dev/null
+++ b/src/socket/SocketWriter.cpp
@@ -0,0 +1,74 @@
+/*
+ This file is part of Ingen.
+ Copyright 2012 David Robillard <http://drobilla.net/>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "SocketWriter.hpp"
+
+namespace Ingen {
+namespace Socket {
+
+static size_t
+socket_sink(const void* buf, size_t len, void* stream)
+{
+ SocketWriter* writer = (SocketWriter*)stream;
+ return write(writer->fd(), buf, len);
+}
+
+SocketWriter::SocketWriter(Shared::LV2URIMap& map,
+ Shared::URIs& uris,
+ const Raul::URI& uri,
+ SharedPtr<Socket> sock)
+ : AtomWriter(map, uris, *this)
+ , _map(map)
+ , _sratom(sratom_new(&map.urid_map_feature()->urid_map))
+ , _uri(uri)
+ , _socket(sock)
+{
+ // Use <path:> as base URI so e.g. </foo/bar> will be a path
+ _base = serd_node_from_string(SERD_URI, (const uint8_t*)"path:");
+
+ serd_uri_parse(_base.buf, &_base_uri);
+
+ _env = serd_env_new(&_base);
+ _writer = serd_writer_new(
+ SERD_TURTLE,
+ (SerdStyle)(SERD_STYLE_RESOLVED|SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED),
+ _env,
+ &_base_uri,
+ socket_sink,
+ this);
+
+ sratom_set_sink(_sratom,
+ (const char*)_base.buf,
+ (SerdStatementSink)serd_writer_write_statement,
+ (SerdEndSink)serd_writer_end_anon,
+ _writer);
+}
+
+SocketWriter::~SocketWriter()
+{
+ sratom_free(_sratom);
+}
+
+void
+SocketWriter::write(const LV2_Atom* msg)
+{
+ sratom_write(_sratom, &_map.urid_unmap_feature()->urid_unmap, 0,
+ NULL, NULL, msg->type, msg->size, LV2_ATOM_BODY(msg));
+ serd_writer_finish(_writer);
+}
+
+} // namespace Socket
+} // namespace Ingen
diff --git a/src/socket/SocketWriter.hpp b/src/socket/SocketWriter.hpp
new file mode 100644
index 00000000..902538f6
--- /dev/null
+++ b/src/socket/SocketWriter.hpp
@@ -0,0 +1,65 @@
+/*
+ This file is part of Ingen.
+ Copyright 2012 David Robillard <http://drobilla.net/>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_SOCKET_SOCKET_WRITER_HPP
+#define INGEN_SOCKET_SOCKET_WRITER_HPP
+
+#include <stdint.h>
+
+#include "ingen/Interface.hpp"
+#include "ingen/shared/AtomSink.hpp"
+#include "ingen/shared/AtomWriter.hpp"
+#include "raul/URI.hpp"
+#include "raul/SharedPtr.hpp"
+#include "sratom/sratom.h"
+
+#include "Socket.hpp"
+
+namespace Ingen {
+namespace Socket {
+
+/** An Interface that writes Turtle messages to a socket.
+ */
+class SocketWriter : public Shared::AtomWriter, public Shared::AtomSink
+{
+public:
+ SocketWriter(Shared::LV2URIMap& map,
+ Shared::URIs& uris,
+ const Raul::URI& uri,
+ SharedPtr<Socket> sock);
+
+ ~SocketWriter();
+
+ void write(const LV2_Atom* msg);
+
+ int fd() { return _socket->fd(); }
+ Raul::URI uri() const { return _uri; }
+
+protected:
+ Shared::LV2URIMap& _map;
+ Sratom* _sratom;
+ SerdNode _base;
+ SerdURI _base_uri;
+ SerdEnv* _env;
+ SerdWriter* _writer;
+ Raul::URI _uri;
+ SharedPtr<Socket> _socket;
+};
+
+} // namespace Socket
+} // namespace Ingen
+
+#endif // INGEN_SOCKET_SOCKET_WRITER_HPP
diff --git a/src/socket/ingen_socket_client.cpp b/src/socket/ingen_socket_client.cpp
new file mode 100644
index 00000000..8b57683c
--- /dev/null
+++ b/src/socket/ingen_socket_client.cpp
@@ -0,0 +1,57 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2012 David Robillard <http://drobilla.net/>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "ingen/shared/Module.hpp"
+#include "ingen/shared/World.hpp"
+#include "raul/log.hpp"
+
+#include "Socket.hpp"
+#include "SocketClient.hpp"
+
+static SharedPtr<Ingen::Interface>
+new_socket_interface(Ingen::Shared::World* world,
+ const std::string& url,
+ SharedPtr<Ingen::Interface> respondee)
+{
+ SharedPtr<Ingen::Socket::Socket> sock(
+ new Ingen::Socket::Socket(Ingen::Socket::Socket::type_from_uri(url)));
+ if (!sock->connect(url)) {
+ return SharedPtr<Ingen::Interface>();
+ }
+ Ingen::Socket::SocketClient* client = new Ingen::Socket::SocketClient(
+ *world,
+ url,
+ sock,
+ respondee);
+ return SharedPtr<Ingen::Interface>(client);
+}
+
+struct IngenSocketClientModule : public Ingen::Shared::Module {
+ void load(Ingen::Shared::World* world) {
+ world->add_interface_factory("unix", &new_socket_interface);
+ world->add_interface_factory("tcp", &new_socket_interface);
+ }
+};
+
+extern "C" {
+
+Ingen::Shared::Module*
+ingen_module_load()
+{
+ return new IngenSocketClientModule();
+}
+
+} // extern "C"
diff --git a/src/socket/wscript b/src/socket/wscript
index e351e0e4..f6705c37 100644
--- a/src/socket/wscript
+++ b/src/socket/wscript
@@ -4,12 +4,26 @@ from waflib.extras import autowaf as autowaf
def build(bld):
if bld.is_defined('HAVE_SOCKET'):
obj = bld(features = 'cxx cxxshlib',
- source = ['SocketReader.cpp',
+ source = ['Socket.cpp',
'SocketListener.cpp',
+ 'SocketReader.cpp',
+ 'SocketWriter.cpp',
'ingen_socket_server.cpp'],
includes = ['.', '../..'],
name = 'libingen_socket_server',
target = 'ingen_socket_server',
install_path = '${LIBDIR}',
use = 'libingen_server')
- autowaf.use_lib(bld, obj, 'RAUL LIBLO')
+ autowaf.use_lib(bld, obj, 'RAUL')
+
+ obj = bld(features = 'cxx cxxshlib',
+ source = ['Socket.cpp',
+ 'SocketReader.cpp',
+ 'SocketWriter.cpp',
+ 'ingen_socket_client.cpp'],
+ includes = ['.', '../..'],
+ name = 'libingen_socket_client',
+ target = 'ingen_socket_client',
+ install_path = '${LIBDIR}',
+ use = 'libingen_server')
+ autowaf.use_lib(bld, obj, 'RAUL')