From 24d998447070dbfef3eaf7762dce7e97c3903801 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 16 Nov 2008 02:49:22 +0000 Subject: TCP notification stream support (not fully implemented yet, but transport stuff is working). Support multiple event sources in the engine. Clean up HTTP/TCP stuff. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@1721 a436a847-0d15-0410-975c-d299462d15a1 --- src/shared/HTTPSender.cpp | 111 +++++++++++++++++++++++++++++++++++++++------- src/shared/HTTPSender.hpp | 21 ++++++--- 2 files changed, 110 insertions(+), 22 deletions(-) (limited to 'src/shared') diff --git a/src/shared/HTTPSender.cpp b/src/shared/HTTPSender.cpp index 20135b2a..7f760786 100644 --- a/src/shared/HTTPSender.cpp +++ b/src/shared/HTTPSender.cpp @@ -20,6 +20,12 @@ #include #include #include +#include +#include +#include +#include + +#include using namespace std; @@ -27,53 +33,126 @@ namespace Ingen { namespace Shared { -HTTPSender::HTTPSender(SoupServer* server, SoupMessage* msg) - : _server(server) - , _msg(msg) +HTTPSender::HTTPSender() + : _listen_port(-1) + , _listen_sock(-1) + , _client_sock(-1) + , _send_state(Immediate) { - soup_message_headers_set_encoding(msg->response_headers, SOUP_ENCODING_CHUNKED); - cout << "Hello?" << endl; - send_chunk("hello"); + Thread::set_name("HTTP Sender"); + + struct sockaddr_in addr; + + // Create listen address + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + // Create listen socket + if ((_listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { + fprintf(stderr, "Error creating listening socket (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + // Bind our socket addresss to the listening socket + if (bind(_listen_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + fprintf(stderr, "Error calling bind (%s)\n", strerror(errno)); + _listen_sock = -1; + } + + // Find port number + socklen_t length = sizeof(addr); + if (getsockname(_listen_sock, (struct sockaddr*)&addr, &length) == -1) { + fprintf(stderr, "Error calling getsockname (%s)\n", strerror(errno)); + _listen_sock = -1; + return; + } + + if (listen(_listen_sock, 1) < 0 ) { + cerr << "Error calling listen: %s" << strerror(errno) << endl; + _listen_sock = -1; + return; + } + + _listen_port = ntohs(addr.sin_port); + cout << "Opening event stream on TCP port " << _listen_port << endl; + start(); } HTTPSender::~HTTPSender() { - cout << "HTTP SENDER EXIT" << endl; - soup_message_body_complete(_msg->response_body); - soup_server_unpause_message(_server, _msg); + stop(); + if (_listen_sock != -1) + close(_listen_sock); + if (_client_sock != -1) + close(_client_sock); +} + +void +HTTPSender::_run() +{ + if (_listen_sock == -1) { + cerr << "Unable to open socket, exiting sender thread" << endl; + return; + } + + // Accept connection + if ((_client_sock = accept(_listen_sock, NULL, NULL) ) < 0) { + cerr << "Error calling accept: " << strerror(errno) << endl; + return; + } + + // Hold connection open and write when signalled + while (true) { + _mutex.lock(); + _signal.wait(_mutex); + + write(_client_sock, _transfer.c_str(), _transfer.length()); + write(_client_sock, "\n\n", 2); + + _mutex.unlock(); + } + + close(_listen_sock); + _listen_sock = -1; } void HTTPSender::bundle_begin() { + _mutex.lock(); _send_state = SendingBundle; + _transfer = ""; + _mutex.unlock(); } void HTTPSender::bundle_end() { + _mutex.lock(); assert(_send_state == SendingBundle); - soup_message_body_append(_msg->response_body, - SOUP_MEMORY_TEMPORARY, _transfer.c_str(), _transfer.length()); - soup_server_unpause_message(_server, _msg); - _transfer = ""; + _signal.broadcast(); _send_state = Immediate; + _mutex.unlock(); } void HTTPSender::send_chunk(const std::string& buf) { + _mutex.lock(); + if (_send_state == Immediate) { - soup_message_body_append(_msg->response_body, - SOUP_MEMORY_TEMPORARY, buf.c_str(), buf.length()); - soup_server_unpause_message(_server, _msg); + _transfer = ""; + _signal.broadcast(); } else { _transfer.append(buf); } + + _mutex.unlock(); } diff --git a/src/shared/HTTPSender.hpp b/src/shared/HTTPSender.hpp index 1025c071..1077b76d 100644 --- a/src/shared/HTTPSender.hpp +++ b/src/shared/HTTPSender.hpp @@ -20,14 +20,15 @@ #include #include -#include +#include +#include "raul/Thread.hpp" namespace Ingen { namespace Shared { -class HTTPSender { +class HTTPSender : public Raul::Thread { public: - HTTPSender(SoupServer* server, SoupMessage* msg); + HTTPSender(); virtual ~HTTPSender(); // Message bundling @@ -38,13 +39,21 @@ public: void transfer_begin() { bundle_begin(); } void transfer_end() { bundle_end(); } + int listen_port() const { return _listen_port; } + protected: - void send_chunk(const std::string& buf); + void _run(); + void send_chunk(const std::string& buf); + enum SendState { Immediate, SendingBundle }; - SoupServer* _server; - SoupMessage* _msg; + Glib::Mutex _mutex; + Glib::Cond _signal; + + int _listen_port; + int _listen_sock; + int _client_sock; SendState _send_state; std::string _transfer; }; -- cgit v1.2.1