Initial debugproxy version 84/185684/1
authorIgor Kotrasinski <i.kotrasinsk@partner.samsung.com>
Tue, 17 Jul 2018 11:53:47 +0000 (13:53 +0200)
committerIgor Kotrasinski <i.kotrasinsk@partner.samsung.com>
Wed, 1 Aug 2018 12:47:02 +0000 (14:47 +0200)
Change-Id: I0f426de44f5856fd082ea9685bdad17bd11a1d52
Signed-off-by: Igor Kotrasinski <i.kotrasinsk@partner.samsung.com>
include/include/config.h
simulatordaemon/debugproxy/CMakeLists.txt
simulatordaemon/debugproxy/inc/AsyncEvent.h [new file with mode: 0644]
simulatordaemon/debugproxy/inc/DebugproxySocket.h [new file with mode: 0644]
simulatordaemon/debugproxy/inc/ProxySession.h [new file with mode: 0644]
simulatordaemon/debugproxy/inc/common.h [new file with mode: 0644]
simulatordaemon/debugproxy/inc/forwarding.h [new file with mode: 0644]
simulatordaemon/debugproxy/src/AsyncEvent.cpp [new file with mode: 0644]
simulatordaemon/debugproxy/src/DebugproxySocket.cpp [new file with mode: 0644]
simulatordaemon/debugproxy/src/ProxySession.cpp [new file with mode: 0644]
simulatordaemon/debugproxy/src/main.cpp

index a5d863c..8e956f2 100644 (file)
@@ -52,6 +52,8 @@
 //keep in sync with systemd/tef-simulator.socket
 #define SIMDAEMON_SOCK_PATH "/var/run/simdaemon"
 #define SIMDAEMON_CTL_PATH "/var/run/simdaemonctl"
+
+#define DEBUGPROXY_SOCK_PATH "/var/run/simdaemon-debugproxy"
 //TEEStub must have write access in this directory (creating socket per TA)
 #define TEE_TASOCK_ROOT "/var/run/"
 
index 90bb085..dfb44ce 100644 (file)
@@ -18,6 +18,9 @@
 #
 
 SET(DEBUGPROXY_SOURCES
+        ${DEBUGPROXY_PATH}/src/AsyncEvent.cpp
+        ${DEBUGPROXY_PATH}/src/DebugproxySocket.cpp
+        ${DEBUGPROXY_PATH}/src/ProxySession.cpp
         ${DEBUGPROXY_PATH}/src/main.cpp
     )
 
@@ -27,6 +30,11 @@ ADD_EXECUTABLE(${TARGET_TEF_SIMULATOR_DEBUGPROXY}
 
 INCLUDE_DIRECTORIES(
         ${DEBUGPROXY_PATH}/inc
+        ${TEF_SIMULATOR_INCLUDE_PATH}/include
+    )
+
+TARGET_LINK_LIBRARIES(${TARGET_TEF_SIMULATOR_DEBUGPROXY}
+    boost_system boost_signals boost_coroutine
     )
 
 INSTALL(TARGETS ${TARGET_TEF_SIMULATOR_DEBUGPROXY} DESTINATION ${BIN_DIR})
diff --git a/simulatordaemon/debugproxy/inc/AsyncEvent.h b/simulatordaemon/debugproxy/inc/AsyncEvent.h
new file mode 100644 (file)
index 0000000..5e2dfd2
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __ASYNC_EVENT_H__
+#define __ASYNC_EVENT_H__
+
+#include <vector>
+#include <memory>
+#include <boost/asio.hpp>
+#include <boost/asio/spawn.hpp>
+
+/* FIXME - signals is already deprecated and signals2 is not yet in the repo */
+#define BOOST_SIGNALS_NO_DEPRECATION_WARNING
+#include <boost/signals.hpp>
+
+#include "common.h"
+
+/* Wrapper for timers for convenient synchronization between coroutines.
+ */
+class AsyncEvent {
+public:
+       AsyncEvent(boost::asio::io_service &io);
+       void wait(yield_ctx yield);
+       void set();
+       boost::signal<void ()> done_signal;
+private:
+       boost::asio::deadline_timer timer;
+};
+
+/* Used to await on any of multiple events. Uses boost signals to ensure that
+ * it can both attach callbacks to AsyncEvent and be destroyed without leaving
+ * references in awaited-on events.
+ */
+class EventList {
+public:
+       typedef std::vector<std::shared_ptr<AsyncEvent>> Events;
+       EventList(Events events, boost::asio::io_service &io);
+       ~EventList();
+       EventList(const EventList &) = delete;
+       EventList& operator=(const EventList &) = delete;
+
+       void operator()();
+       void wait_on_any(yield_ctx yield);
+private:
+       AsyncEvent event;
+       Events awaited_on_events;
+       std::vector<boost::signals::connection> connections;
+};
+
+#endif /* __ASYNC_EVENT_H__ */
diff --git a/simulatordaemon/debugproxy/inc/DebugproxySocket.h b/simulatordaemon/debugproxy/inc/DebugproxySocket.h
new file mode 100644 (file)
index 0000000..f6eaff5
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __DEBUGPROXY_SOCKET_H__
+#define __DEBUGPROXY_SOCKET_H__
+
+#include <string>
+#include <memory>
+#include <boost/asio.hpp>
+#include "common.h"
+#include "AsyncEvent.h"
+
+
+class DebugproxySocket
+{
+public:
+       DebugproxySocket(boost::asio::io_service &io);
+       void start_accept();
+private:
+       void async_accept(yield_ctx yield);
+       void handle_connection(std::shared_ptr<local_sock> local_sock,
+                              yield_ctx yield);
+
+       boost::asio::io_service &io;
+       local::stream_protocol::endpoint ep;
+       local::stream_protocol::acceptor acceptor;
+       std::shared_ptr<AsyncEvent> quit_event;
+};
+
+#endif /* __DEBUGPROXY_SOCKET_H__ */
diff --git a/simulatordaemon/debugproxy/inc/ProxySession.h b/simulatordaemon/debugproxy/inc/ProxySession.h
new file mode 100644 (file)
index 0000000..efe6c90
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __PROXY_SESSION_H__
+#define __PROXY_SESSION_H__
+
+#include <memory>
+#include <boost/asio.hpp>
+#include <boost/asio/spawn.hpp>
+#include "common.h"
+#include "AsyncEvent.h"
+
+
+class ProxySession
+{
+public:
+       ProxySession(std::shared_ptr<local_sock> local_socket,
+                    std::shared_ptr<AsyncEvent> quit_event);
+       ~ProxySession();
+       void async_session(yield_ctx yield);
+private:
+       boost::asio::io_service &io();
+       uint32_t read_forwarded_port(yield_ctx yield);
+       void setup_port_socket(int port, yield_ctx yield);
+       std::shared_ptr<AsyncEvent> start_forwarding();
+       template<typename T>
+       void close_socket(std::shared_ptr<boost::asio::basic_stream_socket<T>> sock);
+       void close_session();
+
+       std::shared_ptr<AsyncEvent> quit_event;
+       std::shared_ptr<local::stream_protocol::socket> local_socket;
+       std::shared_ptr<tcp_sock> port_socket;
+
+       static const boost::posix_time::seconds PORT_TIMEOUT;
+};
+
+#endif /* __PROXY_SESSION_H__ */
diff --git a/simulatordaemon/debugproxy/inc/common.h b/simulatordaemon/debugproxy/inc/common.h
new file mode 100644 (file)
index 0000000..d3e3fd8
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __LOCAL_H__
+#define __LOCAL_H__
+
+#include <boost/asio.hpp>
+#include <boost/asio/spawn.hpp>
+
+namespace local = boost::asio::local;
+namespace ip = boost::asio::ip;
+
+typedef local::stream_protocol::socket local_sock;
+typedef ip::tcp::socket tcp_sock;
+typedef boost::asio::yield_context yield_ctx;
+
+#endif /* __LOCAL_H__ */
diff --git a/simulatordaemon/debugproxy/inc/forwarding.h b/simulatordaemon/debugproxy/inc/forwarding.h
new file mode 100644 (file)
index 0000000..c07858d
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __FORWARDING_H__
+#define __FORWARDING_H__
+
+#include <memory>
+#include <boost/asio.hpp>
+#include "AsyncEvent.h"
+
+namespace local = boost::asio::local;
+namespace ip = boost::asio::ip;
+
+template <typename T>
+using socket_ptr = std::shared_ptr<boost::asio::basic_stream_socket<T>>;
+
+static constexpr int chunk_size = 4096;
+
+template <typename T, typename S>
+void forward(socket_ptr<T> from,
+                   socket_ptr<S> to,
+                   std::shared_ptr<AsyncEvent> connection_end,
+                   yield_ctx yield) {
+       try {
+               char data[chunk_size];
+               while (true) {
+                       std::size_t len = from->async_read_some(
+                               boost::asio::buffer(data), yield);
+                       boost::asio::async_write(
+                               *to, boost::asio::buffer(data, len), yield);
+               }
+       } catch (std::exception &e) {
+               /* TODO - logging */
+               connection_end->set();
+       }
+}
+
+#endif /* __FORWARDING_H__ */
diff --git a/simulatordaemon/debugproxy/src/AsyncEvent.cpp b/simulatordaemon/debugproxy/src/AsyncEvent.cpp
new file mode 100644 (file)
index 0000000..62d83d0
--- /dev/null
@@ -0,0 +1,55 @@
+#include <functional>
+#include <vector>
+#include "AsyncEvent.h"
+
+
+AsyncEvent::AsyncEvent(boost::asio::io_service &io)
+: done_signal()
+, timer(io)
+{
+       this->timer.expires_at(boost::posix_time::pos_infin);
+}
+
+void AsyncEvent::wait(yield_ctx yield)
+{
+       try {
+               this->timer.async_wait(yield);
+       } catch (boost::system::system_error &e) {
+               if (e.code() != boost::asio::error::operation_aborted)
+                       throw;
+       }
+}
+
+void AsyncEvent::set()
+{
+       this->timer.cancel();
+       this->done_signal();
+}
+
+EventList::EventList(EventList::Events events,
+                     boost::asio::io_service &io)
+: event(io)
+, awaited_on_events(events)
+, connections()
+{
+       for (auto event: this->awaited_on_events) {
+               auto conn = event->done_signal.connect(std::ref(*this));
+               this->connections.push_back(conn);
+       }
+}
+
+EventList::~EventList()
+{
+       for (auto conn: this->connections)
+               conn.disconnect();
+}
+
+void EventList::operator()()
+{
+       this->event.set();
+}
+
+void EventList::wait_on_any(yield_ctx yield)
+{
+       this->event.wait(yield);
+}
diff --git a/simulatordaemon/debugproxy/src/DebugproxySocket.cpp b/simulatordaemon/debugproxy/src/DebugproxySocket.cpp
new file mode 100644 (file)
index 0000000..6e2cc8f
--- /dev/null
@@ -0,0 +1,55 @@
+#include <string>
+#include <memory>
+
+#include <boost/bind.hpp>
+#include <boost/asio.hpp>
+#include <boost/asio/spawn.hpp>
+#include <boost/system/system_error.hpp>
+
+#include <config.h>
+
+#include "common.h"
+#include "DebugproxySocket.h"
+#include "ProxySession.h"
+
+DebugproxySocket::DebugproxySocket(boost::asio::io_service &io)
+: io(io)
+, ep(DEBUGPROXY_SOCK_PATH)
+, acceptor(io, ep)
+, quit_event(std::make_shared<AsyncEvent>(io))
+{}
+
+void DebugproxySocket::start_accept()
+{
+       boost::asio::spawn(this->io, boost::bind(&DebugproxySocket::async_accept,
+                                                this, _1));
+}
+
+void DebugproxySocket::async_accept(yield_ctx yield)
+{
+       try {
+               while(true) {
+                       auto sock = std::make_shared<local::stream_protocol::socket>(this->io);
+                       this->acceptor.async_accept(*sock, yield);
+                       boost::asio::spawn(
+                               this->io,
+                               [sock, this](yield_ctx yield) {
+                                       return this->handle_connection(sock, yield);
+                               });
+               }
+       } catch (boost::system::system_error &e) {
+               /* TODO - log */
+               this->quit_event->set();
+       }
+}
+
+void DebugproxySocket::handle_connection(const std::shared_ptr<local_sock> local_sock,
+                                         yield_ctx yield)
+{
+       try {
+               ProxySession session(local_sock, this->quit_event);
+               session.async_session(yield);
+       } catch (boost::system::system_error &e) {
+               /* TODO - log */
+       }
+}
diff --git a/simulatordaemon/debugproxy/src/ProxySession.cpp b/simulatordaemon/debugproxy/src/ProxySession.cpp
new file mode 100644 (file)
index 0000000..377de35
--- /dev/null
@@ -0,0 +1,102 @@
+#include <memory>
+#include <boost/bind.hpp>
+#include <boost/asio/deadline_timer.hpp>
+#include "ProxySession.h"
+#include "forwarding.h"
+#include "common.h"
+
+const boost::posix_time::seconds ProxySession::PORT_TIMEOUT{30};
+
+ProxySession::ProxySession(std::shared_ptr<local_sock> local_socket,
+                          std::shared_ptr<AsyncEvent> quit_event)
+: quit_event(quit_event)
+, local_socket(local_socket)
+, port_socket(std::make_shared<tcp_sock>(local_socket->get_io_service()))
+{}
+
+ProxySession::~ProxySession()
+{
+       this->close_session();
+}
+
+boost::asio::io_service &ProxySession::io()
+{
+       return this->local_socket->get_io_service();
+}
+
+uint32_t ProxySession::read_forwarded_port(yield_ctx yield)
+{
+       uint32_t target_port[1];
+       boost::asio::async_read(
+               *this->local_socket, boost::asio::buffer(target_port), yield);
+       return target_port[0];
+}
+
+void ProxySession::setup_port_socket(int port, yield_ctx yield)
+{
+       ip::tcp::endpoint port_ep(ip::address::from_string("127.0.0.1"), port);
+       auto port_acceptor = std::make_shared<ip::tcp::acceptor>(this->io(), port_ep);
+
+       /* FIXME: We don't want to read data from local socket before
+        * forwarding it, so checking if it closed while we're listening on the
+        * port is difficult. Let's just timeout instead.
+        */
+       auto stop_at_timeout =
+               [this, &io = this->io(), acceptor_ptr = std::weak_ptr<ip::tcp::acceptor>(port_acceptor)]
+               (yield_ctx yield) {
+                       boost::asio::deadline_timer timeout(this->io());
+                       timeout.expires_from_now(ProxySession::PORT_TIMEOUT);
+                       timeout.async_wait(yield);
+                       auto acceptor = acceptor_ptr.lock();
+                       if (!acceptor)
+                               return;
+                       acceptor->cancel();
+       };
+       boost::asio::spawn(this->io(), stop_at_timeout);
+       port_acceptor->async_accept(*this->port_socket, yield);
+}
+
+std::shared_ptr<AsyncEvent> ProxySession::start_forwarding()
+{
+       auto connection_lost_event = std::make_shared<AsyncEvent>(this->io());
+       boost::asio::spawn(
+               this->io(),
+               boost::bind(&forward<local::stream_protocol, ip::tcp>,
+                           this->local_socket, this->port_socket,
+                           connection_lost_event, _1));
+       boost::asio::spawn(
+               this->io(),
+               boost::bind(&forward<ip::tcp, local::stream_protocol>,
+                           this->port_socket, this->local_socket,
+                           connection_lost_event, _1));
+       return connection_lost_event;
+}
+
+void ProxySession::async_session(yield_ctx yield)
+{
+       uint32_t target_port = this->read_forwarded_port(yield);
+       this->setup_port_socket(target_port, yield);
+       auto connection_lost_event = this->start_forwarding();
+
+       EventList events(EventList::Events{this->quit_event,
+                                          connection_lost_event},
+                        this->io());
+       events.wait_on_any(yield);
+}
+
+template <typename T>
+void ProxySession::close_socket(std::shared_ptr<boost::asio::basic_stream_socket<T>> sock)
+{
+       boost::system::error_code ec;
+       if (!sock)
+               return;
+       sock->shutdown(boost::asio::basic_stream_socket<T>::shutdown_both, ec);
+       sock->close();
+       sock = nullptr;
+}
+
+void ProxySession::close_session()
+{
+       this->close_socket(this->local_socket);
+       this->close_socket(this->port_socket);
+}
index ab7c69f..c53ae19 100644 (file)
@@ -1,6 +1,11 @@
-#include <unistd.h>
+#include <boost/asio.hpp>
+#include <DebugproxySocket.h>
 
-int main() {
-       while (true)
-               sleep(1);
+int main()
+{
+       boost::asio::io_service io;
+       DebugproxySocket socket(io);
+       socket.start_accept();
+       io.run();
+       return 0;
 }