//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/"
#
SET(DEBUGPROXY_SOURCES
+ ${DEBUGPROXY_PATH}/src/AsyncEvent.cpp
+ ${DEBUGPROXY_PATH}/src/DebugproxySocket.cpp
+ ${DEBUGPROXY_PATH}/src/ProxySession.cpp
${DEBUGPROXY_PATH}/src/main.cpp
)
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})
--- /dev/null
+#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__ */
--- /dev/null
+#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__ */
--- /dev/null
+#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__ */
--- /dev/null
+#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__ */
--- /dev/null
+#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__ */
--- /dev/null
+#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);
+}
--- /dev/null
+#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 */
+ }
+}
--- /dev/null
+#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);
+}
-#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;
}