summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/file.cc10
-rw-r--r--src/file.hh1
-rw-r--r--src/remote.cc220
-rw-r--r--src/remote.hh9
4 files changed, 138 insertions, 102 deletions
diff --git a/src/file.cc b/src/file.cc
index 1455624b..64061d09 100644
--- a/src/file.cc
+++ b/src/file.cc
@@ -143,6 +143,16 @@ bool fd_readable(int fd)
return select(fd+1, &rfds, nullptr, nullptr, &tv) == 1;
}
+bool fd_writable(int fd)
+{
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ timeval tv{0,0};
+ return select(fd+1, nullptr, &rfds, nullptr, &tv) == 1;
+}
+
String read_fd(int fd, bool text)
{
String content;
diff --git a/src/file.hh b/src/file.hh
index ae1d9db2..89d4e45e 100644
--- a/src/file.hh
+++ b/src/file.hh
@@ -30,6 +30,7 @@ std::pair<StringView, StringView> split_path(StringView path);
String get_kak_binary_path();
bool fd_readable(int fd);
+bool fd_writable(int fd);
String read_fd(int fd, bool text = false);
String read_file(StringView filename, bool text = false);
void write(int fd, StringView data);
diff --git a/src/remote.cc b/src/remote.cc
index 5e8de3f2..743483ad 100644
--- a/src/remote.cc
+++ b/src/remote.cc
@@ -42,7 +42,8 @@ enum class MessageType : char
class MsgWriter
{
public:
- MsgWriter(int sock, MessageType type) : m_socket(sock)
+ MsgWriter(RemoteBuffer& buffer, MessageType type)
+ : m_buffer{buffer}, m_start{(uint32_t)buffer.size()}
{
write(type);
write((uint32_t)0); // message size, to be patched on write
@@ -50,23 +51,13 @@ public:
~MsgWriter() noexcept(false)
{
- uint32_t count = (uint32_t)m_stream.size();
- char* data = m_stream.data();
- *reinterpret_cast<uint32_t*>(data+1) = count;
- while (count > 0)
- {
- int res = ::write(m_socket, data, count);
- if (res <= 0)
- throw remote_error{res ? "peer disconnected"
- : format("socket write failed: {}", strerror(errno))};
- data += res;
- count -= res;
- }
+ uint32_t count = (uint32_t)m_buffer.size() - m_start;
+ *reinterpret_cast<uint32_t*>(m_buffer.data() + m_start + 1) = count;
}
void write(const char* val, size_t size)
{
- m_stream.insert(m_stream.end(), val, val + size);
+ m_buffer.insert(m_buffer.end(), val, val + size);
}
template<typename T>
@@ -139,8 +130,8 @@ public:
}
private:
- Vector<char, MemoryDomain::Remote> m_stream;
- int m_socket;
+ RemoteBuffer& m_buffer;
+ uint32_t m_start;
};
class MsgReader
@@ -344,18 +335,34 @@ private:
MsgReader m_reader;
DisplayCoord m_dimensions;
OnKeyCallback m_on_key;
+ RemoteBuffer m_send_buffer;
SafePtr<Client> m_client;
};
+static bool send_data(int fd, RemoteBuffer& buffer)
+{
+ while (buffer.size() > 0 and fd_writable(fd))
+ {
+ int res = ::write(fd, buffer.data(), buffer.size());
+ if (res <= 0)
+ throw remote_error{res ? "peer disconnected"
+ : format("socket write failed: {}", strerror(errno))};
+ buffer.erase(buffer.begin(), buffer.begin() + res);
+ }
+ return buffer.empty();
+}
RemoteUI::RemoteUI(int socket, DisplayCoord dimensions)
- : m_socket_watcher(socket, FdEvents::Read,
- [this](FDWatcher& watcher, FdEvents, EventMode mode) {
+ : m_socket_watcher(socket, FdEvents::Read | FdEvents::Write,
+ [this](FDWatcher& watcher, FdEvents events, EventMode mode) {
const int sock = watcher.fd();
try
{
- while (fd_readable(sock))
+ if (events & FdEvents::Write and send_data(sock, m_send_buffer))
+ m_socket_watcher.events() &= ~FdEvents::Write;
+
+ while (events & FdEvents::Read and fd_readable(sock))
{
m_reader.read_available(sock);
@@ -377,7 +384,7 @@ RemoteUI::RemoteUI(int socket, DisplayCoord dimensions)
}
catch (const remote_error& err)
{
- write_to_debug_buffer(format("Error while reading remote message: {}", err.what()));
+ write_to_debug_buffer(format("Error while transfering remote messages: {}", err.what()));
ClientManager::instance().remove_client(*m_client, false);
}
}),
@@ -396,72 +403,81 @@ void RemoteUI::menu_show(ConstArrayView<DisplayLine> choices,
DisplayCoord anchor, Face fg, Face bg,
MenuStyle style)
{
- MsgWriter msg{m_socket_watcher.fd(), MessageType::MenuShow};
+ MsgWriter msg{m_send_buffer, MessageType::MenuShow};
msg.write(choices);
msg.write(anchor);
msg.write(fg);
msg.write(bg);
msg.write(style);
+ m_socket_watcher.events() |= FdEvents::Write;
}
void RemoteUI::menu_select(int selected)
{
- MsgWriter msg{m_socket_watcher.fd(), MessageType::MenuSelect};
+ MsgWriter msg{m_send_buffer, MessageType::MenuSelect};
msg.write(selected);
+ m_socket_watcher.events() |= FdEvents::Write;
}
void RemoteUI::menu_hide()
{
- MsgWriter msg{m_socket_watcher.fd(), MessageType::MenuHide};
+ MsgWriter msg{m_send_buffer, MessageType::MenuHide};
+ m_socket_watcher.events() |= FdEvents::Write;
}
void RemoteUI::info_show(StringView title, StringView content,
DisplayCoord anchor, Face face,
InfoStyle style)
{
- MsgWriter msg{m_socket_watcher.fd(), MessageType::InfoShow};
+ MsgWriter msg{m_send_buffer, MessageType::InfoShow};
msg.write(title);
msg.write(content);
msg.write(anchor);
msg.write(face);
msg.write(style);
+ m_socket_watcher.events() |= FdEvents::Write;
}
void RemoteUI::info_hide()
{
- MsgWriter msg{m_socket_watcher.fd(), MessageType::InfoHide};
+ MsgWriter msg{m_send_buffer, MessageType::InfoHide};
+ m_socket_watcher.events() |= FdEvents::Write;
}
void RemoteUI::draw(const DisplayBuffer& display_buffer,
const Face& default_face,
const Face& padding_face)
{
- MsgWriter msg{m_socket_watcher.fd(), MessageType::Draw};
+ MsgWriter msg{m_send_buffer, MessageType::Draw};
msg.write(display_buffer);
msg.write(default_face);
msg.write(padding_face);
+ m_socket_watcher.events() |= FdEvents::Write;
}
void RemoteUI::draw_status(const DisplayLine& status_line,
const DisplayLine& mode_line,
const Face& default_face)
{
- MsgWriter msg{m_socket_watcher.fd(), MessageType::DrawStatus};
+ MsgWriter msg{m_send_buffer, MessageType::DrawStatus};
msg.write(status_line);
msg.write(mode_line);
msg.write(default_face);
+ m_socket_watcher.events() |= FdEvents::Write;
}
void RemoteUI::refresh(bool force)
{
- MsgWriter msg{m_socket_watcher.fd(), MessageType::Refresh};
+ MsgWriter msg{m_send_buffer, MessageType::Refresh};
msg.write(force);
+ m_socket_watcher.events() |= FdEvents::Write;
}
void RemoteUI::set_ui_options(const Options& options)
{
- MsgWriter msg{m_socket_watcher.fd(), MessageType::SetOptions};
+ MsgWriter msg{m_send_buffer, MessageType::SetOptions};
msg.write(options);
+ m_socket_watcher.events() |= FdEvents::Write;
}
static sockaddr_un session_addr(StringView session)
@@ -500,83 +516,90 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr<UserInterface>&&
int sock = connect_to(session);
{
- MsgWriter msg{sock, MessageType::Connect};
+ MsgWriter msg{m_send_buffer, MessageType::Connect};
msg.write(init_command);
msg.write(m_ui->dimensions());
msg.write(env_vars);
}
m_ui->set_on_key([this](Key key){
- MsgWriter msg(m_socket_watcher->fd(), MessageType::Key);
+ MsgWriter msg(m_send_buffer, MessageType::Key);
msg.write(key);
+ m_socket_watcher->events() |= FdEvents::Write;
});
MsgReader reader;
- m_socket_watcher.reset(new FDWatcher{sock, FdEvents::Read,
- [this, reader](FDWatcher& watcher, FdEvents, EventMode) mutable {
+ m_socket_watcher.reset(new FDWatcher{sock, FdEvents::Read | FdEvents::Write,
+ [this, reader](FDWatcher& watcher, FdEvents events, EventMode) mutable {
const int sock = watcher.fd();
- while (fd_readable(sock) and not reader.ready())
+ if (events & FdEvents::Write and send_data(sock, m_send_buffer))
+ m_socket_watcher->events() &= ~FdEvents::Write;
+
+ while (events & FdEvents::Read and
+ not reader.ready() and fd_readable(sock))
+ {
reader.read_available(sock);
- if (not reader.ready())
- return;
+ if (not reader.ready())
+ continue;
- auto clear_reader = on_scope_end([&reader] { reader.reset(); });
- switch (reader.type())
- {
- case MessageType::MenuShow:
- {
- auto choices = reader.read_vector<DisplayLine>();
- auto anchor = reader.read<DisplayCoord>();
- auto fg = reader.read<Face>();
- auto bg = reader.read<Face>();
- auto style = reader.read<MenuStyle>();
- m_ui->menu_show(choices, anchor, fg, bg, style);
- break;
- }
- case MessageType::MenuSelect:
- m_ui->menu_select(reader.read<int>());
- break;
- case MessageType::MenuHide:
- m_ui->menu_hide();
- break;
- case MessageType::InfoShow:
- {
- auto title = reader.read<String>();
- auto content = reader.read<String>();
- auto anchor = reader.read<DisplayCoord>();
- auto face = reader.read<Face>();
- auto style = reader.read<InfoStyle>();
- m_ui->info_show(title, content, anchor, face, style);
- break;
- }
- case MessageType::InfoHide:
- m_ui->info_hide();
- break;
- case MessageType::Draw:
- {
- auto display_buffer = reader.read<DisplayBuffer>();
- auto default_face = reader.read<Face>();
- auto padding_face = reader.read<Face>();
- m_ui->draw(display_buffer, default_face, padding_face);
- break;
- }
- case MessageType::DrawStatus:
- {
- auto status_line = reader.read<DisplayLine>();
- auto mode_line = reader.read<DisplayLine>();
- auto default_face = reader.read<Face>();
- m_ui->draw_status(status_line, mode_line, default_face);
- break;
- }
- case MessageType::Refresh:
- m_ui->refresh(reader.read<bool>());
- break;
- case MessageType::SetOptions:
- m_ui->set_ui_options(reader.read_idmap<String, MemoryDomain::Options>());
- break;
- default:
- kak_assert(false);
+ auto clear_reader = on_scope_end([&reader] { reader.reset(); });
+ switch (reader.type())
+ {
+ case MessageType::MenuShow:
+ {
+ auto choices = reader.read_vector<DisplayLine>();
+ auto anchor = reader.read<DisplayCoord>();
+ auto fg = reader.read<Face>();
+ auto bg = reader.read<Face>();
+ auto style = reader.read<MenuStyle>();
+ m_ui->menu_show(choices, anchor, fg, bg, style);
+ break;
+ }
+ case MessageType::MenuSelect:
+ m_ui->menu_select(reader.read<int>());
+ break;
+ case MessageType::MenuHide:
+ m_ui->menu_hide();
+ break;
+ case MessageType::InfoShow:
+ {
+ auto title = reader.read<String>();
+ auto content = reader.read<String>();
+ auto anchor = reader.read<DisplayCoord>();
+ auto face = reader.read<Face>();
+ auto style = reader.read<InfoStyle>();
+ m_ui->info_show(title, content, anchor, face, style);
+ break;
+ }
+ case MessageType::InfoHide:
+ m_ui->info_hide();
+ break;
+ case MessageType::Draw:
+ {
+ auto display_buffer = reader.read<DisplayBuffer>();
+ auto default_face = reader.read<Face>();
+ auto padding_face = reader.read<Face>();
+ m_ui->draw(display_buffer, default_face, padding_face);
+ break;
+ }
+ case MessageType::DrawStatus:
+ {
+ auto status_line = reader.read<DisplayLine>();
+ auto mode_line = reader.read<DisplayLine>();
+ auto default_face = reader.read<Face>();
+ m_ui->draw_status(status_line, mode_line, default_face);
+ break;
+ }
+ case MessageType::Refresh:
+ m_ui->refresh(reader.read<bool>());
+ break;
+ case MessageType::SetOptions:
+ m_ui->set_ui_options(reader.read_idmap<String, MemoryDomain::Options>());
+ break;
+ default:
+ kak_assert(false);
+ }
}
}});
}
@@ -585,8 +608,12 @@ void send_command(StringView session, StringView command)
{
int sock = connect_to(session);
auto close_sock = on_scope_end([sock]{ close(sock); });
- MsgWriter msg{sock, MessageType::Command};
- msg.write(command);
+ RemoteBuffer buffer;
+ {
+ MsgWriter msg{buffer, MessageType::Command};
+ msg.write(command);
+ }
+ write(sock, {buffer.data(), buffer.data() + buffer.size()});
}
@@ -613,11 +640,8 @@ private:
const int sock = m_socket_watcher.fd();
try
{
- do
- {
+ while (not m_reader.ready() and fd_readable(sock))
m_reader.read_available(sock);
- }
- while (fd_readable(sock) and not m_reader.ready());
if (not m_reader.ready())
return;
diff --git a/src/remote.hh b/src/remote.hh
index 38340d48..6aaac49d 100644
--- a/src/remote.hh
+++ b/src/remote.hh
@@ -4,6 +4,7 @@
#include "env_vars.hh"
#include "exception.hh"
#include "utils.hh"
+#include "vector.hh"
#include <memory>
@@ -12,14 +13,13 @@ namespace Kakoune
struct remote_error : runtime_error
{
- remote_error(String error)
- : runtime_error{std::move(error)}
- {}
+ using runtime_error::runtime_error;
};
class FDWatcher;
class UserInterface;
-struct Key;
+
+using RemoteBuffer = Vector<char, MemoryDomain::Remote>;
// A remote client handle communication between a client running on the server
// and a user interface running on the local process.
@@ -32,6 +32,7 @@ public:
private:
std::unique_ptr<UserInterface> m_ui;
std::unique_ptr<FDWatcher> m_socket_watcher;
+ RemoteBuffer m_send_buffer;
};
void send_command(StringView session, StringView command);