diff --git a/repos/gems/src/server/tcp_terminal/README b/repos/gems/src/server/tcp_terminal/README index d230f62e0..bede9524a 100644 --- a/repos/gems/src/server/tcp_terminal/README +++ b/repos/gems/src/server/tcp_terminal/README @@ -4,9 +4,13 @@ to be used for each client is defined in as session policy in the config node of the TCP server: ! -! +! ! ! +If only a port is described in the policy the TCP terminal will listen on +that port for incomming connections. If an IP address is provided additionally, +it connects to the IP address using the given port. + For an example of how to use the TCP terminal, please refer to the run script at 'gems/run/tcp_terminal.run'. diff --git a/repos/gems/src/server/tcp_terminal/main.cc b/repos/gems/src/server/tcp_terminal/main.cc index 1d1a55413..8f96c9f83 100644 --- a/repos/gems/src/server/tcp_terminal/main.cc +++ b/repos/gems/src/server/tcp_terminal/main.cc @@ -110,9 +110,37 @@ class Open_socket : public Genode::List::Element return listen_sd; } + /** + * Establish remote connection + * + * \return socket descriptor used for the remote TCP connection + */ + static int _remote_connect(char const * ip, int tcp_port) + { + int sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sd == -1) { + Genode::error("socket creation failed"); + return -1; + } + + sockaddr_in sockaddr; + sockaddr.sin_family = PF_INET; + sockaddr.sin_port = htons (tcp_port); + sockaddr.sin_addr.s_addr = inet_addr(ip); + + if (connect(sd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { + Genode::error("connect to ", ip, ":", tcp_port, " failed"); + return -1; + } + + Genode::log("connected to ", ip, ":", tcp_port, "..."); + return sd; + } + public: Open_socket(int tcp_port); + Open_socket(char const * ip_addr, int tcp_port); ~Open_socket(); @@ -131,11 +159,29 @@ class Open_socket : public Genode::List::Element */ int sd() const { return _sd; } + /** + * Return true if TCP connection is established + * + * If the return value is false, we are still in listening more + * and have not yet called 'accept()'. + */ + bool connection_established() const { return _sd != -1; } + /** * Register signal handler to be notified once we accepted the TCP * connection */ - void connected_sigh(Genode::Signal_context_capability sigh) { _connected_sigh = sigh; } + void connected_sigh(Genode::Signal_context_capability sigh) + { + _connected_sigh = sigh; + + /* + * Inform client about the finished initialization of the terminal + * session + */ + if (_connected_sigh.valid() && connection_established()) + Genode::Signal_transmitter(_connected_sigh).submit(); + } /** * Register signal handler to be notified when data is available for @@ -162,7 +208,7 @@ class Open_socket : public Genode::List::Element socklen_t len = sizeof(addr); _sd = accept(_listen_sd, &addr, &len); - if (_sd != -1) + if (connection_established()) Genode::log("connection established"); /* @@ -173,14 +219,6 @@ class Open_socket : public Genode::List::Element Genode::Signal_transmitter(_connected_sigh).submit(); } - /** - * Return true if TCP connection is established - * - * If the return value is false, we are still in listening more - * and have not yet called 'accept()'. - */ - bool connection_established() const { return _sd != -1; } - /** * Fetch data from socket into internal read buffer */ @@ -406,6 +444,15 @@ Open_socket::Open_socket(int tcp_port) } +Open_socket::Open_socket(char const * ip_addr, int tcp_port) +: + _listen_sd(_remote_connect(ip_addr, tcp_port)), _sd(_listen_sd), + _read_buf_bytes_used(0), _read_buf_bytes_read(0) +{ + open_socket_pool()->insert(this); +} + + Open_socket::~Open_socket() { if (_sd != -1) close(_sd); @@ -433,6 +480,13 @@ class Terminal::Session_component : public Genode::Rpc_object Ip; + Ip ip_addr = policy.attribute_value("ip", Ip()); + Libc::with_libc([&] () { + session = new (md_alloc()) + Session_component(_env, io_buffer_size, ip_addr.string(), tcp_port); }); + } else { + Libc::with_libc([&] () { + session = new (md_alloc()) + Session_component(_env, io_buffer_size, tcp_port); }); + } return session; }