move remoting code to remote.cc
ClientAccepter is now Server's implementation detail and all socket logic are isolated in remote.cc
This commit is contained in:
parent
b309d1df61
commit
0b45a725e4
75
src/main.cc
75
src/main.cc
|
@ -27,14 +27,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
using namespace Kakoune;
|
using namespace Kakoune;
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
|
@ -686,50 +680,6 @@ std::unordered_map<Key, std::function<void (Context& context)>> keymap =
|
||||||
|
|
||||||
void run_unit_tests();
|
void run_unit_tests();
|
||||||
|
|
||||||
struct Server : public Singleton<Server>
|
|
||||||
{
|
|
||||||
Server()
|
|
||||||
{
|
|
||||||
m_filename = "/tmp/kak-" + int_to_str(getpid());
|
|
||||||
|
|
||||||
int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
fcntl(listen_sock, F_SETFD, FD_CLOEXEC);
|
|
||||||
sockaddr_un addr;
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
strncpy(addr.sun_path, m_filename.c_str(), sizeof(addr.sun_path) - 1);
|
|
||||||
|
|
||||||
if (bind(listen_sock, (sockaddr*) &addr, sizeof(sockaddr_un)) == -1)
|
|
||||||
throw runtime_error("unable to bind listen socket " + m_filename);
|
|
||||||
|
|
||||||
if (listen(listen_sock, 4) == -1)
|
|
||||||
throw runtime_error("unable to listen on socket " + m_filename);
|
|
||||||
|
|
||||||
auto accepter = [](FDWatcher& watcher) {
|
|
||||||
sockaddr_un client_addr;
|
|
||||||
socklen_t client_addr_len = sizeof(sockaddr_un);
|
|
||||||
int sock = accept(watcher.fd(), (sockaddr*) &client_addr, &client_addr_len);
|
|
||||||
if (sock == -1)
|
|
||||||
throw runtime_error("accept failed");
|
|
||||||
fcntl(sock, F_SETFD, FD_CLOEXEC);
|
|
||||||
|
|
||||||
new ClientAccepter{sock};
|
|
||||||
};
|
|
||||||
m_listener.reset(new FDWatcher{listen_sock, accepter});
|
|
||||||
}
|
|
||||||
|
|
||||||
~Server()
|
|
||||||
{
|
|
||||||
unlink(m_filename.c_str());
|
|
||||||
close(m_listener->fd());
|
|
||||||
}
|
|
||||||
|
|
||||||
const String& filename() const { return m_filename; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
String m_filename;
|
|
||||||
std::unique_ptr<FDWatcher> m_listener;
|
|
||||||
};
|
|
||||||
|
|
||||||
void register_env_vars()
|
void register_env_vars()
|
||||||
{
|
{
|
||||||
ShellManager& shell_manager = ShellManager::instance();
|
ShellManager& shell_manager = ShellManager::instance();
|
||||||
|
@ -804,24 +754,6 @@ void create_local_client(const String& init_command)
|
||||||
std::unique_ptr<UserInterface>{ui}, init_command);
|
std::unique_ptr<UserInterface>{ui}, init_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteClient* connect_to(const String& pid, const String& init_command)
|
|
||||||
{
|
|
||||||
auto filename = "/tmp/kak-" + pid;
|
|
||||||
|
|
||||||
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
fcntl(sock, F_SETFD, FD_CLOEXEC);
|
|
||||||
sockaddr_un addr;
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
strncpy(addr.sun_path, filename.c_str(), sizeof(addr.sun_path) - 1);
|
|
||||||
if (connect(sock, (sockaddr*)&addr, sizeof(addr.sun_path)) == -1)
|
|
||||||
throw runtime_error("connect to " + filename + " failed");
|
|
||||||
|
|
||||||
NCursesUI* ui = new NCursesUI{};
|
|
||||||
RemoteClient* remote_client = new RemoteClient{sock, ui, init_command};
|
|
||||||
|
|
||||||
return remote_client;
|
|
||||||
}
|
|
||||||
|
|
||||||
void signal_handler(int signal)
|
void signal_handler(int signal)
|
||||||
{
|
{
|
||||||
endwin();
|
endwin();
|
||||||
|
@ -862,8 +794,9 @@ int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::unique_ptr<RemoteClient> client(
|
auto client = connect_to(parser.option_value("c"),
|
||||||
connect_to(parser.option_value("c"), init_command));
|
std::unique_ptr<UserInterface>{new NCursesUI{}},
|
||||||
|
init_command);
|
||||||
while (true)
|
while (true)
|
||||||
event_manager.handle_next_events();
|
event_manager.handle_next_events();
|
||||||
}
|
}
|
||||||
|
|
137
src/remote.cc
137
src/remote.cc
|
@ -9,6 +9,11 @@
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
@ -303,9 +308,9 @@ void RemoteUI::set_input_callback(InputCallback callback)
|
||||||
m_input_callback = std::move(callback);
|
m_input_callback = std::move(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteClient::RemoteClient(int socket, UserInterface* ui,
|
RemoteClient::RemoteClient(int socket, std::unique_ptr<UserInterface>&& ui,
|
||||||
const String& init_command)
|
const String& init_command)
|
||||||
: m_ui(ui), m_dimensions(ui->dimensions()),
|
: m_ui(std::move(ui)), m_dimensions(m_ui->dimensions()),
|
||||||
m_socket_watcher{socket, [this](FDWatcher&){ process_next_message(); }}
|
m_socket_watcher{socket, [this](FDWatcher&){ process_next_message(); }}
|
||||||
{
|
{
|
||||||
Message msg(socket);
|
Message msg(socket);
|
||||||
|
@ -380,46 +385,112 @@ void RemoteClient::write_next_key()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientAccepter::ClientAccepter(int socket)
|
std::unique_ptr<RemoteClient> connect_to(const String& pid, std::unique_ptr<UserInterface>&& ui,
|
||||||
: m_socket_watcher(socket, [this](FDWatcher&) { handle_available_input(); }) {}
|
const String& init_command)
|
||||||
|
|
||||||
void ClientAccepter::handle_available_input()
|
|
||||||
{
|
{
|
||||||
int socket = m_socket_watcher.fd();
|
auto filename = "/tmp/kak-" + pid;
|
||||||
timeval tv{ 0, 0 };
|
|
||||||
fd_set rfds;
|
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
do
|
fcntl(sock, F_SETFD, FD_CLOEXEC);
|
||||||
|
sockaddr_un addr;
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(addr.sun_path, filename.c_str(), sizeof(addr.sun_path) - 1);
|
||||||
|
if (connect(sock, (sockaddr*)&addr, sizeof(addr.sun_path)) == -1)
|
||||||
|
throw runtime_error("connect to " + filename + " failed");
|
||||||
|
|
||||||
|
return std::unique_ptr<RemoteClient>{new RemoteClient{sock, std::move(ui), init_command}};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// A client accepter handle a connection until it closes or a nul byte is
|
||||||
|
// recieved. Everything recieved before is considered to be a command.
|
||||||
|
//
|
||||||
|
// * When a nul byte is recieved, the socket is handed to a new Client along
|
||||||
|
// with the command.
|
||||||
|
// * When the connection is closed, the command is run in an empty context.
|
||||||
|
class ClientAccepter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClientAccepter(int socket)
|
||||||
|
: m_socket_watcher(socket, [this](FDWatcher&) { handle_available_input(); }) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handle_available_input()
|
||||||
{
|
{
|
||||||
char c;
|
int socket = m_socket_watcher.fd();
|
||||||
int res = ::read(socket, &c, 1);
|
timeval tv{ 0, 0 };
|
||||||
if (res <= 0)
|
fd_set rfds;
|
||||||
|
do
|
||||||
{
|
{
|
||||||
if (not m_buffer.empty()) try
|
char c;
|
||||||
|
int res = ::read(socket, &c, 1);
|
||||||
|
if (res <= 0)
|
||||||
{
|
{
|
||||||
Context context{};
|
if (not m_buffer.empty()) try
|
||||||
CommandManager::instance().execute(m_buffer, context);
|
{
|
||||||
|
Context context{};
|
||||||
|
CommandManager::instance().execute(m_buffer, context);
|
||||||
|
}
|
||||||
|
catch (runtime_error& e)
|
||||||
|
{
|
||||||
|
write_debug("error running command '" + m_buffer + "' : " + e.description());
|
||||||
|
}
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (runtime_error& e)
|
if (c == 0) // end of initial command stream, go to interactive ui mode
|
||||||
{
|
{
|
||||||
write_debug("error running command '" + m_buffer + "' : " + e.description());
|
ClientManager::instance().create_client(
|
||||||
|
std::unique_ptr<UserInterface>{new RemoteUI{socket}}, m_buffer);
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
delete this;
|
else
|
||||||
return;
|
m_buffer += c;
|
||||||
}
|
|
||||||
if (c == 0) // end of initial command stream, go to interactive ui mode
|
|
||||||
{
|
|
||||||
ClientManager::instance().create_client(
|
|
||||||
std::unique_ptr<UserInterface>{new RemoteUI{socket}}, m_buffer);
|
|
||||||
delete this;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
m_buffer += c;
|
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_SET(socket, &rfds);
|
FD_SET(socket, &rfds);
|
||||||
|
}
|
||||||
|
while (select(socket+1, &rfds, NULL, NULL, &tv) == 1);
|
||||||
}
|
}
|
||||||
while (select(socket+1, &rfds, NULL, NULL, &tv) == 1);
|
|
||||||
|
String m_buffer;
|
||||||
|
FDWatcher m_socket_watcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
Server::Server()
|
||||||
|
{
|
||||||
|
m_filename = "/tmp/kak-" + int_to_str(getpid());
|
||||||
|
|
||||||
|
int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
fcntl(listen_sock, F_SETFD, FD_CLOEXEC);
|
||||||
|
sockaddr_un addr;
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(addr.sun_path, m_filename.c_str(), sizeof(addr.sun_path) - 1);
|
||||||
|
|
||||||
|
if (bind(listen_sock, (sockaddr*) &addr, sizeof(sockaddr_un)) == -1)
|
||||||
|
throw runtime_error("unable to bind listen socket " + m_filename);
|
||||||
|
|
||||||
|
if (listen(listen_sock, 4) == -1)
|
||||||
|
throw runtime_error("unable to listen on socket " + m_filename);
|
||||||
|
|
||||||
|
auto accepter = [](FDWatcher& watcher) {
|
||||||
|
sockaddr_un client_addr;
|
||||||
|
socklen_t client_addr_len = sizeof(sockaddr_un);
|
||||||
|
int sock = accept(watcher.fd(), (sockaddr*) &client_addr, &client_addr_len);
|
||||||
|
if (sock == -1)
|
||||||
|
throw runtime_error("accept failed");
|
||||||
|
fcntl(sock, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
|
new ClientAccepter{sock};
|
||||||
|
};
|
||||||
|
m_listener.reset(new FDWatcher{listen_sock, accepter});
|
||||||
|
}
|
||||||
|
|
||||||
|
Server::~Server()
|
||||||
|
{
|
||||||
|
unlink(m_filename.c_str());
|
||||||
|
close(m_listener->fd());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,39 +10,36 @@ namespace Kakoune
|
||||||
|
|
||||||
struct peer_disconnected {};
|
struct peer_disconnected {};
|
||||||
|
|
||||||
// A client accepter handle a connection until it closes or a nul byte is
|
|
||||||
// recieved. Everything recieved before is considered to be a command.
|
|
||||||
//
|
|
||||||
// * When a nul byte is recieved, the socket is handed to a new Client along
|
|
||||||
// with the command.
|
|
||||||
// * When the connection is closed, the command is run in an empty context.
|
|
||||||
class ClientAccepter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ClientAccepter(int socket);
|
|
||||||
private:
|
|
||||||
void handle_available_input();
|
|
||||||
|
|
||||||
String m_buffer;
|
|
||||||
FDWatcher m_socket_watcher;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A remote client handle communication between a client running on the server
|
// A remote client handle communication between a client running on the server
|
||||||
// and a user interface running on the local process.
|
// and a user interface running on the local process.
|
||||||
class RemoteClient
|
class RemoteClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RemoteClient(int socket, UserInterface* ui,
|
RemoteClient(int socket, std::unique_ptr<UserInterface>&& ui,
|
||||||
const String& init_command);
|
const String& init_command);
|
||||||
|
|
||||||
|
private:
|
||||||
void process_next_message();
|
void process_next_message();
|
||||||
void write_next_key();
|
void write_next_key();
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<UserInterface> m_ui;
|
std::unique_ptr<UserInterface> m_ui;
|
||||||
DisplayCoord m_dimensions;
|
DisplayCoord m_dimensions;
|
||||||
FDWatcher m_socket_watcher;
|
FDWatcher m_socket_watcher;
|
||||||
};
|
};
|
||||||
|
std::unique_ptr<RemoteClient> connect_to(const String& pid,
|
||||||
|
std::unique_ptr<UserInterface>&& ui,
|
||||||
|
const String& init_command);
|
||||||
|
|
||||||
|
struct Server : public Singleton<Server>
|
||||||
|
{
|
||||||
|
Server();
|
||||||
|
~Server();
|
||||||
|
const String& filename() const { return m_filename; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
String m_filename;
|
||||||
|
std::unique_ptr<FDWatcher> m_listener;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user