2012-10-23 22:55:44 +02:00
|
|
|
#include "remote.hh"
|
|
|
|
|
2013-03-12 18:53:18 +01:00
|
|
|
#include "buffer_manager.hh"
|
2015-06-06 12:54:48 +02:00
|
|
|
#include "buffer_utils.hh"
|
2013-04-09 20:05:40 +02:00
|
|
|
#include "client_manager.hh"
|
2013-03-12 18:53:18 +01:00
|
|
|
#include "command_manager.hh"
|
2013-04-09 20:05:40 +02:00
|
|
|
#include "display_buffer.hh"
|
|
|
|
#include "event_manager.hh"
|
2015-08-23 15:13:46 +02:00
|
|
|
#include "file.hh"
|
2017-03-07 02:12:37 +01:00
|
|
|
#include "hash_map.hh"
|
2017-01-21 13:14:44 +01:00
|
|
|
#include "optional.hh"
|
2016-11-29 20:53:11 +01:00
|
|
|
#include "user_interface.hh"
|
2012-10-23 22:55:44 +02:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
2013-03-13 19:59:39 +01:00
|
|
|
#include <sys/un.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <unistd.h>
|
Fix build on FreeBSD
file.cc:390:21: error: use of undeclared identifier 'rename'; did you mean 'devname'?
if (replace and rename(temp_filename, zfilename) != 0)
^~~~~~
devname
/usr/include/stdlib.h:277:7: note: 'devname' declared here
char *devname(__dev_t, __mode_t);
^
file.cc:390:28: error: cannot initialize a parameter of type '__dev_t' (aka 'unsigned long') with an lvalue of type 'char [1024]'
if (replace and rename(temp_filename, zfilename) != 0)
^~~~~~~~~~~~~
/usr/include/stdlib.h:277:22: note: passing argument to parameter here
char *devname(__dev_t, __mode_t);
^
2 errors generated.
---
highlighters.cc:1110:13: error: use of undeclared identifier 'snprintf'; did you mean 'vswprintf'?
snprintf(buffer, 16, format, std::abs(line_to_format));
^~~~~~~~
vswprintf
/usr/include/wchar.h:139:5: note: 'vswprintf' declared here
int vswprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict,
^
highlighters.cc:1110:22: error: cannot initialize a parameter of type 'wchar_t *' with an lvalue of type 'char [16]'
snprintf(buffer, 16, format, std::abs(line_to_format));
^~~~~~
/usr/include/wchar.h:139:35: note: passing argument to parameter here
int vswprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict,
^
2 errors generated.
---
json_ui.cc:60:13: error: use of undeclared identifier 'sprintf'; did you mean 'swprintf'?
sprintf(buf, "\\u%04x", *next);
^~~~~~~
swprintf
/usr/include/wchar.h:133:5: note: 'swprintf' declared here
int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict,
^
json_ui.cc:60:21: error: cannot initialize a parameter of type 'wchar_t *' with an lvalue of type 'char [7]'
sprintf(buf, "\\u%04x", *next);
^~~
/usr/include/wchar.h:133:34: note: passing argument to parameter here
int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict,
^
json_ui.cc:74:9: error: use of undeclared identifier 'sprintf'
sprintf(buffer, R"("#%02x%02x%02x")", color.r, color.g, color.b);
^
3 errors generated.
---
regex_impl.cc:1039:9: error: use of undeclared identifier 'sprintf'; did you mean 'swprintf'?
sprintf(buf, " %03d ", count++);
^~~~~~~
swprintf
/usr/include/wchar.h:133:5: note: 'swprintf' declared here
int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict,
^
regex_impl.cc:1039:17: error: cannot initialize a parameter of type 'wchar_t *' with an lvalue of type 'char [20]'
sprintf(buf, " %03d ", count++);
^~~
/usr/include/wchar.h:133:34: note: passing argument to parameter here
int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict,
^
regex_impl.cc:1197:17: error: use of undeclared identifier 'puts'
{ if (dump) puts(dump_regex(*this).c_str()); }
^
regex_impl.cc:1208:18: note: in instantiation of member function 'Kakoune::(anonymous namespace)::TestVM<Kakoune::RegexMode::Forward>::TestVM' requested here
TestVM<> vm{R"(a*b)"};
^
regex_impl.cc:1197:17: error: use of undeclared identifier 'puts'
{ if (dump) puts(dump_regex(*this).c_str()); }
^
regex_impl.cc:1283:56: note: in instantiation of member function 'Kakoune::(anonymous namespace)::TestVM<5>::TestVM' requested here
TestVM<RegexMode::Forward | RegexMode::Search> vm{R"(f.*a(.*o))"};
^
regex_impl.cc:1197:17: error: use of undeclared identifier 'puts'
{ if (dump) puts(dump_regex(*this).c_str()); }
^
regex_impl.cc:1423:57: note: in instantiation of member function 'Kakoune::(anonymous namespace)::TestVM<6>::TestVM' requested here
TestVM<RegexMode::Backward | RegexMode::Search> vm{R"(fo{1,})"};
^
5 errors generated.
---
remote.cc:829:9: error: use of undeclared identifier 'rename'; did you mean 'devname'?
if (rename(old_socket_file.c_str(), new_socket_file.c_str()) != 0)
^~~~~~
devname
/usr/include/stdlib.h:277:7: note: 'devname' declared here
char *devname(__dev_t, __mode_t);
^
remote.cc:829:16: error: cannot initialize a parameter of type '__dev_t' (aka 'unsigned long') with an rvalue of type 'const char *'
if (rename(old_socket_file.c_str(), new_socket_file.c_str()) != 0)
^~~~~~~~~~~~~~~~~~~~~~~
/usr/include/stdlib.h:277:22: note: passing argument to parameter here
char *devname(__dev_t, __mode_t);
^
2 errors generated.
---
string_utils.cc:126:20: error: use of undeclared identifier 'sprintf'; did you mean 'swprintf'?
res.m_length = sprintf(res.m_data, "%i", val);
^~~~~~~
swprintf
/usr/include/wchar.h:133:5: note: 'swprintf' declared here
int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict,
^
string_utils.cc:126:28: error: cannot initialize a parameter of type 'wchar_t *' with an lvalue of type 'char [15]'
res.m_length = sprintf(res.m_data, "%i", val);
^~~~~~~~~~
/usr/include/wchar.h:133:34: note: passing argument to parameter here
int swprintf(wchar_t * __restrict, size_t n, const wchar_t * __restrict,
^
string_utils.cc:133:20: error: use of undeclared identifier 'sprintf'; did you mean 'swprintf'?
res.m_length = sprintf(res.m_data, "%u", val);
^~~~~~~
swprintf
[...]
2019-07-01 16:32:14 +02:00
|
|
|
#include <stdio.h>
|
2017-11-06 05:45:14 +01:00
|
|
|
#include <string.h>
|
2015-09-15 14:32:26 +02:00
|
|
|
#include <pwd.h>
|
2013-03-13 19:59:39 +01:00
|
|
|
#include <fcntl.h>
|
2019-01-24 13:15:22 +01:00
|
|
|
#include <errno.h>
|
2013-03-13 19:59:39 +01:00
|
|
|
|
2012-10-23 22:55:44 +02:00
|
|
|
|
|
|
|
namespace Kakoune
|
|
|
|
{
|
|
|
|
|
2017-06-26 12:27:18 +02:00
|
|
|
enum class MessageType : uint8_t
|
2012-10-23 22:55:44 +02:00
|
|
|
{
|
2016-08-31 20:33:02 +02:00
|
|
|
Unknown,
|
2016-08-31 10:24:07 +02:00
|
|
|
Connect,
|
|
|
|
Command,
|
2012-10-23 22:55:44 +02:00
|
|
|
MenuShow,
|
|
|
|
MenuSelect,
|
|
|
|
MenuHide,
|
2012-12-14 19:04:34 +01:00
|
|
|
InfoShow,
|
|
|
|
InfoHide,
|
2014-04-15 20:19:44 +02:00
|
|
|
Draw,
|
2015-06-17 22:28:02 +02:00
|
|
|
DrawStatus,
|
2017-04-12 11:39:17 +02:00
|
|
|
SetCursor,
|
2014-11-11 00:29:16 +01:00
|
|
|
Refresh,
|
2016-08-31 10:24:07 +02:00
|
|
|
SetOptions,
|
2017-08-23 08:22:23 +02:00
|
|
|
Exit,
|
|
|
|
Key,
|
2012-10-23 22:55:44 +02:00
|
|
|
};
|
|
|
|
|
2016-08-31 20:33:02 +02:00
|
|
|
class MsgWriter
|
2012-10-23 22:55:44 +02:00
|
|
|
{
|
|
|
|
public:
|
2016-12-01 21:11:09 +01:00
|
|
|
MsgWriter(RemoteBuffer& buffer, MessageType type)
|
|
|
|
: m_buffer{buffer}, m_start{(uint32_t)buffer.size()}
|
2016-08-31 10:24:07 +02:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(type);
|
|
|
|
write_field((uint32_t)0); // message size, to be patched on write
|
2016-08-31 10:24:07 +02:00
|
|
|
}
|
|
|
|
|
2018-05-03 14:44:39 +02:00
|
|
|
~MsgWriter()
|
2012-10-26 13:45:32 +02:00
|
|
|
{
|
2016-12-01 21:11:09 +01:00
|
|
|
uint32_t count = (uint32_t)m_buffer.size() - m_start;
|
2017-06-26 12:27:18 +02:00
|
|
|
memcpy(m_buffer.data() + m_start + sizeof(MessageType), &count, sizeof(uint32_t));
|
2012-10-26 13:45:32 +02:00
|
|
|
}
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2019-05-22 20:03:49 +02:00
|
|
|
template<typename ...Args>
|
|
|
|
void write(Args&&... args)
|
|
|
|
{
|
|
|
|
(write_field(std::forward<Args>(args)), ...);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void write_raw(const char* val, size_t size)
|
2012-10-23 22:55:44 +02:00
|
|
|
{
|
2016-12-01 21:11:09 +01:00
|
|
|
m_buffer.insert(m_buffer.end(), val, val + size);
|
2012-10-23 22:55:44 +02:00
|
|
|
}
|
|
|
|
|
2012-12-10 18:55:11 +01:00
|
|
|
template<typename T>
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(const T& val)
|
2012-12-10 18:55:11 +01:00
|
|
|
{
|
2018-04-07 04:32:31 +02:00
|
|
|
static_assert(std::is_trivially_copyable<T>::value, "");
|
2019-05-22 20:03:49 +02:00
|
|
|
write_raw((const char*)&val, sizeof(val));
|
2013-04-03 19:20:38 +02:00
|
|
|
}
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(StringView str)
|
2012-12-10 18:55:11 +01:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(str.length());
|
|
|
|
write_raw(str.data(), (int)str.length());
|
2012-12-10 18:55:11 +01:00
|
|
|
};
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(const String& str)
|
2014-04-30 20:39:52 +02:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(StringView{str});
|
2014-04-30 20:39:52 +02:00
|
|
|
}
|
|
|
|
|
2012-12-10 18:55:11 +01:00
|
|
|
template<typename T>
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(ConstArrayView<T> view)
|
2012-12-10 18:55:11 +01:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field<uint32_t>(view.size());
|
2012-12-10 18:55:11 +01:00
|
|
|
for (auto& val : view)
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(val);
|
2013-04-03 19:20:38 +02:00
|
|
|
}
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2015-01-14 20:16:32 +01:00
|
|
|
template<typename T, MemoryDomain domain>
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(const Vector<T, domain>& vec)
|
2012-12-10 18:55:11 +01:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(ConstArrayView<T>(vec));
|
2012-12-10 18:55:11 +01:00
|
|
|
}
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2017-03-07 02:12:37 +01:00
|
|
|
template<typename Key, typename Val, MemoryDomain domain>
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(const HashMap<Key, Val, domain>& map)
|
2014-04-07 22:25:44 +02:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field<uint32_t>(map.size());
|
2014-04-07 22:25:44 +02:00
|
|
|
for (auto& val : map)
|
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(val.key);
|
|
|
|
write_field(val.value);
|
2014-04-07 22:25:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-21 13:14:44 +01:00
|
|
|
template<typename T>
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(const Optional<T>& val)
|
2017-01-21 13:14:44 +01:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field((bool)val);
|
2017-01-21 13:14:44 +01:00
|
|
|
if (val)
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(*val);
|
2017-01-21 13:14:44 +01:00
|
|
|
}
|
|
|
|
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(Color color)
|
2013-05-07 18:52:23 +02:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(color.color);
|
2020-05-02 04:57:36 +02:00
|
|
|
if (color.isRGB())
|
2013-05-07 18:52:23 +02:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(color.r);
|
|
|
|
write_field(color.g);
|
|
|
|
write_field(color.b);
|
2013-05-07 18:52:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(const DisplayAtom& atom)
|
2012-12-10 18:55:11 +01:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(atom.content());
|
|
|
|
write_field(atom.face);
|
2012-12-10 18:55:11 +01:00
|
|
|
}
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(const DisplayLine& line)
|
2012-12-10 18:55:11 +01:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(line.atoms());
|
2012-12-10 18:55:11 +01:00
|
|
|
}
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2019-05-22 20:03:49 +02:00
|
|
|
void write_field(const DisplayBuffer& display_buffer)
|
2012-12-10 18:55:11 +01:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
write_field(display_buffer.lines());
|
2012-12-10 18:55:11 +01:00
|
|
|
}
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2012-12-10 18:55:11 +01:00
|
|
|
private:
|
2016-12-01 21:11:09 +01:00
|
|
|
RemoteBuffer& m_buffer;
|
|
|
|
uint32_t m_start;
|
2012-12-10 18:55:11 +01:00
|
|
|
};
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2016-08-31 20:33:02 +02:00
|
|
|
class MsgReader
|
2012-10-26 13:45:32 +02:00
|
|
|
{
|
2019-04-20 18:43:52 +02:00
|
|
|
private:
|
|
|
|
template<typename T>
|
|
|
|
struct Reader {
|
|
|
|
static T read(MsgReader& reader)
|
|
|
|
{
|
|
|
|
static_assert(std::is_trivially_copyable<T>::value, "");
|
|
|
|
T res;
|
|
|
|
reader.read(reinterpret_cast<char*>(&res), sizeof(T));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T, MemoryDomain domain>
|
|
|
|
struct Reader<Vector<T,domain>> {
|
|
|
|
static Vector<T, domain> read(MsgReader& reader)
|
|
|
|
{
|
|
|
|
uint32_t size = Reader<uint32_t>::read(reader);
|
|
|
|
Vector<T,domain> res;
|
|
|
|
res.reserve(size);
|
|
|
|
while (size--)
|
|
|
|
res.push_back(std::move(Reader<T>::read(reader)));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename Key, typename Value, MemoryDomain domain>
|
|
|
|
struct Reader<HashMap<Key, Value, domain>> {
|
|
|
|
static HashMap<Key, Value, domain> read(MsgReader& reader)
|
|
|
|
{
|
|
|
|
uint32_t size = Reader<uint32_t>::read(reader);
|
|
|
|
HashMap<Key, Value, domain> res;
|
|
|
|
res.reserve(size);
|
|
|
|
while (size--)
|
|
|
|
{
|
|
|
|
auto key = Reader<Key>::read(reader);
|
|
|
|
auto val = Reader<Value>::read(reader);
|
|
|
|
res.insert({std::move(key), std::move(val)});
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
struct Reader<Optional<T>> {
|
|
|
|
static Optional<T> read(MsgReader& reader)
|
|
|
|
{
|
|
|
|
if (not Reader<bool>::read(reader))
|
|
|
|
return {};
|
|
|
|
return Reader<T>::read(reader);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-08-31 20:33:02 +02:00
|
|
|
public:
|
|
|
|
void read_available(int sock)
|
2012-11-19 19:07:32 +01:00
|
|
|
{
|
2016-08-31 20:33:02 +02:00
|
|
|
if (m_write_pos < header_size)
|
|
|
|
{
|
|
|
|
m_stream.resize(header_size);
|
|
|
|
read_from_socket(sock, header_size - m_write_pos);
|
|
|
|
if (m_write_pos == header_size)
|
2016-12-01 20:45:23 +01:00
|
|
|
{
|
|
|
|
if (size() < header_size)
|
2016-12-20 11:34:48 +01:00
|
|
|
throw disconnected{"invalid message received"};
|
2016-08-31 20:33:02 +02:00
|
|
|
m_stream.resize(size());
|
2016-12-01 20:45:23 +01:00
|
|
|
}
|
2016-08-31 20:33:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
read_from_socket(sock, size() - m_write_pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ready() const
|
|
|
|
{
|
|
|
|
return m_write_pos >= header_size and m_write_pos == size();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t size() const
|
|
|
|
{
|
2018-04-05 00:52:33 +02:00
|
|
|
kak_assert(m_write_pos >= header_size);
|
2017-06-26 12:27:18 +02:00
|
|
|
uint32_t res;
|
|
|
|
memcpy(&res, m_stream.data() + sizeof(MessageType), sizeof(uint32_t));
|
|
|
|
return res;
|
2016-08-31 20:33:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MessageType type() const
|
|
|
|
{
|
2018-04-05 00:52:33 +02:00
|
|
|
kak_assert(m_write_pos >= header_size);
|
2016-08-31 20:33:02 +02:00
|
|
|
return *reinterpret_cast<const MessageType*>(m_stream.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
void read(char* buffer, size_t size)
|
|
|
|
{
|
2016-09-04 18:54:07 +02:00
|
|
|
if (m_read_pos + size > m_stream.size())
|
2016-12-20 11:34:48 +01:00
|
|
|
throw disconnected{"tried to read after message end"};
|
2016-08-31 20:33:02 +02:00
|
|
|
memcpy(buffer, m_stream.data() + m_read_pos, size);
|
|
|
|
m_read_pos += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T read()
|
|
|
|
{
|
2019-04-20 18:43:52 +02:00
|
|
|
return Reader<T>::read(*this);
|
2017-01-21 13:14:44 +01:00
|
|
|
}
|
|
|
|
|
2020-05-10 07:21:49 +02:00
|
|
|
Optional<int> ancillary_fd()
|
|
|
|
{
|
|
|
|
auto res = m_ancillary_fd;
|
|
|
|
m_ancillary_fd.reset();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
~MsgReader()
|
|
|
|
{
|
|
|
|
m_ancillary_fd.map(close);
|
|
|
|
}
|
|
|
|
|
2016-08-31 20:33:02 +02:00
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
m_stream.resize(0);
|
|
|
|
m_write_pos = 0;
|
|
|
|
m_read_pos = header_size;
|
2020-05-10 07:21:49 +02:00
|
|
|
m_ancillary_fd.map(close);
|
2016-08-31 20:33:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void read_from_socket(int sock, size_t size)
|
|
|
|
{
|
2016-12-01 20:45:23 +01:00
|
|
|
kak_assert(m_write_pos + size <= m_stream.size());
|
2020-05-10 07:21:49 +02:00
|
|
|
iovec io{m_stream.data() + m_write_pos, size};
|
|
|
|
alignas(cmsghdr) char fdbuf[CMSG_SPACE(sizeof(int))];
|
|
|
|
|
|
|
|
msghdr msg{};
|
|
|
|
msg.msg_iov = &io;
|
|
|
|
msg.msg_iovlen = 1;
|
|
|
|
msg.msg_control = fdbuf;
|
|
|
|
msg.msg_controllen = sizeof(fdbuf);
|
|
|
|
|
2020-05-17 13:27:56 +02:00
|
|
|
int res = recvmsg(sock, &msg, 0);
|
2016-11-29 20:12:56 +01:00
|
|
|
if (res <= 0)
|
2017-08-23 08:22:23 +02:00
|
|
|
throw disconnected{format("socket read failed: {}", strerror(errno))};
|
2020-05-10 07:21:49 +02:00
|
|
|
|
2016-08-31 20:33:02 +02:00
|
|
|
m_write_pos += res;
|
2020-05-10 07:21:49 +02:00
|
|
|
|
|
|
|
if (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
|
|
|
|
cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS && cmsg->cmsg_len == CMSG_LEN(sizeof(int)))
|
|
|
|
{
|
|
|
|
m_ancillary_fd.map(close);
|
|
|
|
memcpy(&m_ancillary_fd.emplace(), CMSG_DATA(cmsg), sizeof(int));
|
2020-05-17 13:27:56 +02:00
|
|
|
fcntl(*m_ancillary_fd, F_SETFD, FD_CLOEXEC);
|
2020-05-10 07:21:49 +02:00
|
|
|
}
|
2016-08-31 20:33:02 +02:00
|
|
|
}
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2016-08-31 20:33:02 +02:00
|
|
|
static constexpr uint32_t header_size = sizeof(MessageType) + sizeof(uint32_t);
|
|
|
|
Vector<char, MemoryDomain::Remote> m_stream;
|
2020-05-10 07:21:49 +02:00
|
|
|
Optional<int> m_ancillary_fd;
|
2016-08-31 20:33:02 +02:00
|
|
|
uint32_t m_write_pos = 0;
|
|
|
|
uint32_t m_read_pos = header_size;
|
|
|
|
};
|
2016-11-29 20:12:56 +01:00
|
|
|
|
2012-10-23 22:55:44 +02:00
|
|
|
template<>
|
2019-04-20 18:43:52 +02:00
|
|
|
struct MsgReader::Reader<String> {
|
|
|
|
static String read(MsgReader& reader)
|
2014-04-23 23:21:04 +02:00
|
|
|
{
|
2019-04-20 18:43:52 +02:00
|
|
|
ByteCount length = Reader<ByteCount>::read(reader);
|
|
|
|
String res;
|
|
|
|
if (length > 0)
|
|
|
|
{
|
|
|
|
res.force_size((int)length);
|
|
|
|
reader.read(&res[0_byte], (int)length);
|
|
|
|
}
|
|
|
|
return res;
|
2014-04-23 23:21:04 +02:00
|
|
|
}
|
2019-04-20 18:43:52 +02:00
|
|
|
};
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2013-05-07 18:52:23 +02:00
|
|
|
template<>
|
2019-04-20 18:43:52 +02:00
|
|
|
struct MsgReader::Reader<Color> {
|
|
|
|
static Color read(MsgReader& reader)
|
2013-05-07 18:52:23 +02:00
|
|
|
{
|
2019-04-20 18:43:52 +02:00
|
|
|
Color res;
|
|
|
|
res.color = Reader<Color::NamedColor>::read(reader);
|
2020-05-02 04:57:36 +02:00
|
|
|
if (res.isRGB())
|
2019-04-20 18:43:52 +02:00
|
|
|
{
|
|
|
|
res.r = Reader<unsigned char>::read(reader);
|
|
|
|
res.g = Reader<unsigned char>::read(reader);
|
|
|
|
res.b = Reader<unsigned char>::read(reader);
|
|
|
|
}
|
|
|
|
return res;
|
2013-05-07 18:52:23 +02:00
|
|
|
}
|
2019-04-20 18:43:52 +02:00
|
|
|
};
|
2012-10-23 22:55:44 +02:00
|
|
|
|
|
|
|
template<>
|
2019-04-20 18:43:52 +02:00
|
|
|
struct MsgReader::Reader<DisplayAtom> {
|
|
|
|
static DisplayAtom read(MsgReader& reader)
|
|
|
|
{
|
|
|
|
String content = Reader<String>::read(reader);
|
|
|
|
return {std::move(content), Reader<Face>::read(reader)};
|
|
|
|
}
|
|
|
|
};
|
2016-08-31 20:33:02 +02:00
|
|
|
|
2012-10-23 22:55:44 +02:00
|
|
|
template<>
|
2019-04-20 18:43:52 +02:00
|
|
|
struct MsgReader::Reader<DisplayLine> {
|
|
|
|
static DisplayLine read(MsgReader& reader)
|
|
|
|
{
|
|
|
|
return {Reader<Vector<DisplayAtom>>::read(reader)};
|
|
|
|
}
|
|
|
|
};
|
2012-10-23 22:55:44 +02:00
|
|
|
|
|
|
|
template<>
|
2019-04-20 18:43:52 +02:00
|
|
|
struct MsgReader::Reader<DisplayBuffer> {
|
|
|
|
static DisplayBuffer read(MsgReader& reader)
|
|
|
|
{
|
|
|
|
DisplayBuffer db;
|
|
|
|
db.lines() = Reader<Vector<DisplayLine>>::read(reader);
|
|
|
|
return db;
|
|
|
|
}
|
|
|
|
};
|
2012-10-23 22:55:44 +02:00
|
|
|
|
2014-04-07 22:25:44 +02:00
|
|
|
|
2012-12-18 21:20:36 +01:00
|
|
|
class RemoteUI : public UserInterface
|
|
|
|
{
|
|
|
|
public:
|
2016-09-22 21:36:26 +02:00
|
|
|
RemoteUI(int socket, DisplayCoord dimensions);
|
2017-01-08 23:30:15 +01:00
|
|
|
~RemoteUI() override;
|
2012-12-18 21:20:36 +01:00
|
|
|
|
2018-04-29 14:27:28 +02:00
|
|
|
bool is_ok() const override { return m_socket_watcher.fd() != -1; }
|
2015-10-05 02:25:23 +02:00
|
|
|
void menu_show(ConstArrayView<DisplayLine> choices,
|
2016-09-22 21:36:26 +02:00
|
|
|
DisplayCoord anchor, Face fg, Face bg,
|
2013-04-04 13:53:47 +02:00
|
|
|
MenuStyle style) override;
|
2012-12-18 21:20:36 +01:00
|
|
|
void menu_select(int selected) override;
|
|
|
|
void menu_hide() override;
|
|
|
|
|
2019-11-22 11:48:26 +01:00
|
|
|
void info_show(const DisplayLine& title, const DisplayLineList& content,
|
2016-09-22 21:36:26 +02:00
|
|
|
DisplayCoord anchor, Face face,
|
2014-11-08 18:59:38 +01:00
|
|
|
InfoStyle style) override;
|
2012-12-18 21:20:36 +01:00
|
|
|
void info_hide() override;
|
|
|
|
|
|
|
|
void draw(const DisplayBuffer& display_buffer,
|
2016-02-17 14:32:05 +01:00
|
|
|
const Face& default_face,
|
|
|
|
const Face& padding_face) override;
|
2015-06-17 22:28:02 +02:00
|
|
|
|
|
|
|
void draw_status(const DisplayLine& status_line,
|
|
|
|
const DisplayLine& mode_line,
|
|
|
|
const Face& default_face) override;
|
2012-12-18 21:20:36 +01:00
|
|
|
|
2017-04-12 11:39:17 +02:00
|
|
|
void set_cursor(CursorMode mode, DisplayCoord coord) override;
|
|
|
|
|
2016-03-07 14:54:20 +01:00
|
|
|
void refresh(bool force) override;
|
2014-04-15 20:19:44 +02:00
|
|
|
|
2016-11-29 22:35:53 +01:00
|
|
|
DisplayCoord dimensions() override { return m_dimensions; }
|
2012-12-18 21:20:36 +01:00
|
|
|
|
2016-11-29 22:35:53 +01:00
|
|
|
void set_on_key(OnKeyCallback callback) override
|
|
|
|
{ m_on_key = std::move(callback); }
|
2013-01-11 19:17:21 +01:00
|
|
|
|
2014-11-11 00:29:16 +01:00
|
|
|
void set_ui_options(const Options& options) override;
|
|
|
|
|
2017-08-23 08:22:23 +02:00
|
|
|
void exit(int status);
|
|
|
|
|
2012-12-18 21:20:36 +01:00
|
|
|
private:
|
2019-05-22 20:03:49 +02:00
|
|
|
template<typename ...Args>
|
|
|
|
void send_message(MessageType type, Args&&... args)
|
|
|
|
{
|
|
|
|
MsgWriter msg{m_send_buffer, type};
|
|
|
|
msg.write(std::forward<Args>(args)...);
|
|
|
|
m_socket_watcher.events() |= FdEvents::Write;
|
|
|
|
}
|
|
|
|
|
2016-11-29 22:35:53 +01:00
|
|
|
FDWatcher m_socket_watcher;
|
|
|
|
MsgReader m_reader;
|
|
|
|
DisplayCoord m_dimensions;
|
|
|
|
OnKeyCallback m_on_key;
|
2016-12-01 21:11:09 +01:00
|
|
|
RemoteBuffer m_send_buffer;
|
2012-12-18 21:20:36 +01:00
|
|
|
};
|
|
|
|
|
2020-05-10 07:21:49 +02:00
|
|
|
static bool send_data(int fd, RemoteBuffer& buffer, Optional<int> ancillary_fd = {})
|
2016-12-01 21:11:09 +01:00
|
|
|
{
|
2017-03-17 00:08:10 +01:00
|
|
|
while (not buffer.empty() and fd_writable(fd))
|
2016-12-01 21:11:09 +01:00
|
|
|
{
|
2020-05-10 07:21:49 +02:00
|
|
|
iovec io{buffer.data(), buffer.size()};
|
|
|
|
alignas(cmsghdr) char fdbuf[CMSG_SPACE(sizeof(int))];
|
|
|
|
|
|
|
|
msghdr msg{};
|
|
|
|
msg.msg_iov = &io;
|
|
|
|
msg.msg_iovlen = 1;
|
|
|
|
if (ancillary_fd)
|
|
|
|
{
|
|
|
|
msg.msg_control = fdbuf;
|
|
|
|
msg.msg_controllen = sizeof(fdbuf);
|
|
|
|
|
|
|
|
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
|
|
|
|
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
|
|
|
cmsg->cmsg_level = SOL_SOCKET;
|
|
|
|
cmsg->cmsg_type = SCM_RIGHTS;
|
|
|
|
memcpy(CMSG_DATA(cmsg), &*ancillary_fd, sizeof(int));
|
|
|
|
}
|
|
|
|
|
|
|
|
int res = sendmsg(fd, &msg, 0);
|
|
|
|
if (res <= 0)
|
|
|
|
throw disconnected{format("socket write failed: {}", strerror(errno))};
|
|
|
|
buffer.erase(buffer.begin(), buffer.begin() + res);
|
2016-12-01 21:11:09 +01:00
|
|
|
}
|
|
|
|
return buffer.empty();
|
|
|
|
}
|
2012-12-18 21:20:36 +01:00
|
|
|
|
2016-09-22 21:36:26 +02:00
|
|
|
RemoteUI::RemoteUI(int socket, DisplayCoord dimensions)
|
2021-03-10 23:02:02 +01:00
|
|
|
: m_socket_watcher(socket, FdEvents::Read | FdEvents::Write, EventMode::Urgent,
|
2018-05-17 14:55:53 +02:00
|
|
|
[this](FDWatcher& watcher, FdEvents events, EventMode) {
|
2016-09-04 18:54:07 +02:00
|
|
|
const int sock = watcher.fd();
|
|
|
|
try
|
|
|
|
{
|
2016-12-01 21:11:09 +01:00
|
|
|
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))
|
2016-11-29 22:35:53 +01:00
|
|
|
{
|
2016-09-04 18:54:07 +02:00
|
|
|
m_reader.read_available(sock);
|
|
|
|
|
2016-11-29 22:35:53 +01:00
|
|
|
if (not m_reader.ready())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (m_reader.type() != MessageType::Key)
|
2016-09-04 18:54:07 +02:00
|
|
|
{
|
2018-04-29 14:27:28 +02:00
|
|
|
m_socket_watcher.close_fd();
|
|
|
|
return;
|
2016-09-04 18:54:07 +02:00
|
|
|
}
|
2016-11-29 22:35:53 +01:00
|
|
|
|
|
|
|
auto key = m_reader.read<Key>();
|
|
|
|
m_reader.reset();
|
|
|
|
if (key.modifiers == Key::Modifiers::Resize)
|
|
|
|
m_dimensions = key.coord();
|
|
|
|
m_on_key(key);
|
2016-09-04 18:54:07 +02:00
|
|
|
}
|
|
|
|
}
|
2016-12-20 11:34:48 +01:00
|
|
|
catch (const disconnected& err)
|
2016-09-04 18:54:07 +02:00
|
|
|
{
|
2016-12-01 21:11:09 +01:00
|
|
|
write_to_debug_buffer(format("Error while transfering remote messages: {}", err.what()));
|
2018-04-29 14:27:28 +02:00
|
|
|
m_socket_watcher.close_fd();
|
2016-11-29 22:35:53 +01:00
|
|
|
}
|
2016-09-04 18:54:07 +02:00
|
|
|
}),
|
2015-11-18 14:43:43 +01:00
|
|
|
m_dimensions(dimensions)
|
2012-11-19 19:06:32 +01:00
|
|
|
{
|
2015-06-06 12:54:48 +02:00
|
|
|
write_to_debug_buffer(format("remote client connected: {}", m_socket_watcher.fd()));
|
2012-11-19 19:06:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
RemoteUI::~RemoteUI()
|
|
|
|
{
|
2017-08-23 08:22:23 +02:00
|
|
|
// Try to send the remaining data if possible, as it might contain the desired exit status
|
2017-09-07 13:37:58 +02:00
|
|
|
try
|
|
|
|
{
|
2019-05-23 04:41:31 +02:00
|
|
|
if (m_socket_watcher.fd() != -1)
|
|
|
|
send_data(m_socket_watcher.fd(), m_send_buffer);
|
2017-09-07 13:37:58 +02:00
|
|
|
}
|
|
|
|
catch (disconnected&)
|
|
|
|
{
|
|
|
|
}
|
2017-08-23 08:22:23 +02:00
|
|
|
|
2015-06-06 12:54:48 +02:00
|
|
|
write_to_debug_buffer(format("remote client disconnected: {}", m_socket_watcher.fd()));
|
2014-12-03 14:56:02 +01:00
|
|
|
m_socket_watcher.close_fd();
|
2012-11-19 19:06:32 +01:00
|
|
|
}
|
|
|
|
|
2015-10-05 02:25:23 +02:00
|
|
|
void RemoteUI::menu_show(ConstArrayView<DisplayLine> choices,
|
2016-09-22 21:36:26 +02:00
|
|
|
DisplayCoord anchor, Face fg, Face bg,
|
2013-04-04 13:53:47 +02:00
|
|
|
MenuStyle style)
|
2012-10-23 22:55:44 +02:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::MenuShow, choices, anchor, fg, bg, style);
|
2012-10-23 22:55:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RemoteUI::menu_select(int selected)
|
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::MenuSelect, selected);
|
2012-10-23 22:55:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RemoteUI::menu_hide()
|
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::MenuHide);
|
2012-10-23 22:55:44 +02:00
|
|
|
}
|
|
|
|
|
2019-11-22 11:48:26 +01:00
|
|
|
void RemoteUI::info_show(const DisplayLine& title, const DisplayLineList& content,
|
2016-09-22 21:36:26 +02:00
|
|
|
DisplayCoord anchor, Face face,
|
2014-11-08 18:59:38 +01:00
|
|
|
InfoStyle style)
|
2012-12-14 19:04:34 +01:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::InfoShow, title, content, anchor, face, style);
|
2012-12-14 19:04:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void RemoteUI::info_hide()
|
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::InfoHide);
|
2012-12-14 19:04:34 +01:00
|
|
|
}
|
|
|
|
|
2012-10-23 22:55:44 +02:00
|
|
|
void RemoteUI::draw(const DisplayBuffer& display_buffer,
|
2016-02-17 14:32:05 +01:00
|
|
|
const Face& default_face,
|
|
|
|
const Face& padding_face)
|
2012-10-23 22:55:44 +02:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::Draw, display_buffer, default_face, padding_face);
|
2015-06-17 22:28:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RemoteUI::draw_status(const DisplayLine& status_line,
|
|
|
|
const DisplayLine& mode_line,
|
|
|
|
const Face& default_face)
|
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::DrawStatus, status_line, mode_line, default_face);
|
2012-10-23 22:55:44 +02:00
|
|
|
}
|
|
|
|
|
2017-04-12 11:39:17 +02:00
|
|
|
void RemoteUI::set_cursor(CursorMode mode, DisplayCoord coord)
|
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::SetCursor, mode, coord);
|
2017-04-12 11:39:17 +02:00
|
|
|
}
|
|
|
|
|
2016-03-07 14:54:20 +01:00
|
|
|
void RemoteUI::refresh(bool force)
|
2014-04-15 20:19:44 +02:00
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::Refresh, force);
|
2014-04-15 20:19:44 +02:00
|
|
|
}
|
|
|
|
|
2014-11-11 00:29:16 +01:00
|
|
|
void RemoteUI::set_ui_options(const Options& options)
|
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::SetOptions, options);
|
2014-11-11 00:29:16 +01:00
|
|
|
}
|
|
|
|
|
2017-08-23 08:22:23 +02:00
|
|
|
void RemoteUI::exit(int status)
|
|
|
|
{
|
2019-05-22 20:03:49 +02:00
|
|
|
send_message(MessageType::Exit, status);
|
2017-08-23 08:22:23 +02:00
|
|
|
}
|
|
|
|
|
2018-08-24 16:47:11 +02:00
|
|
|
String get_user_name()
|
2017-12-04 07:27:54 +01:00
|
|
|
{
|
2018-08-24 16:47:11 +02:00
|
|
|
auto pw = getpwuid(geteuid());
|
|
|
|
if (pw)
|
|
|
|
return pw->pw_name;
|
|
|
|
return getenv("USER");
|
2017-12-04 07:27:54 +01:00
|
|
|
}
|
|
|
|
|
2021-05-01 07:29:50 +02:00
|
|
|
const String& session_directory()
|
2019-08-20 22:13:21 +02:00
|
|
|
{
|
2021-05-01 07:29:50 +02:00
|
|
|
static String session_dir = [] {
|
|
|
|
StringView xdg_runtime_dir = getenv("XDG_RUNTIME_DIR");
|
|
|
|
if (not xdg_runtime_dir.empty())
|
|
|
|
{
|
|
|
|
if (struct stat st; stat(xdg_runtime_dir.zstr(), &st) == 0 && st.st_uid == geteuid())
|
|
|
|
return format("{}/kakoune", xdg_runtime_dir);
|
|
|
|
else
|
|
|
|
write_to_debug_buffer("XDG_RUNTIME_DIR does not exist or not owned by current user, using tmpdir");
|
|
|
|
}
|
|
|
|
return format("{}/kakoune-{}", tmpdir(), get_user_name());
|
|
|
|
}();
|
|
|
|
return session_dir;
|
2019-07-29 19:38:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
String session_path(StringView session)
|
|
|
|
{
|
2022-04-07 13:23:10 +02:00
|
|
|
if (not all_of(session, is_identifier))
|
|
|
|
throw runtime_error{format("invalid session name: '{}'", session)};
|
2019-08-20 22:13:21 +02:00
|
|
|
return format("{}/{}", session_directory(), session);
|
2019-07-29 19:38:11 +02:00
|
|
|
}
|
|
|
|
|
2014-11-06 14:54:18 +01:00
|
|
|
static sockaddr_un session_addr(StringView session)
|
2012-10-25 12:51:01 +02:00
|
|
|
{
|
2014-11-06 14:54:18 +01:00
|
|
|
sockaddr_un addr;
|
|
|
|
addr.sun_family = AF_UNIX;
|
2022-04-07 13:36:15 +02:00
|
|
|
String path = session_path(session);
|
|
|
|
if (path.length() + 1 > sizeof addr.sun_path)
|
|
|
|
throw runtime_error{format("socket path too long: '{}'", path)};
|
|
|
|
strcpy(addr.sun_path, path.c_str());
|
2014-11-06 14:54:18 +01:00
|
|
|
return addr;
|
|
|
|
}
|
2014-11-05 14:57:12 +01:00
|
|
|
|
2014-11-06 14:54:18 +01:00
|
|
|
static int connect_to(StringView session)
|
|
|
|
{
|
2014-11-05 14:57:12 +01:00
|
|
|
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
fcntl(sock, F_SETFD, FD_CLOEXEC);
|
2014-11-06 14:54:18 +01:00
|
|
|
sockaddr_un addr = session_addr(session);
|
2014-11-05 14:57:12 +01:00
|
|
|
if (connect(sock, (sockaddr*)&addr, sizeof(addr.sun_path)) == -1)
|
2016-12-20 11:34:48 +01:00
|
|
|
throw disconnected(format("connect to {} failed", addr.sun_path));
|
2014-11-06 14:54:18 +01:00
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
2016-06-06 20:28:56 +02:00
|
|
|
bool check_session(StringView session)
|
|
|
|
{
|
|
|
|
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
auto close_sock = on_scope_end([sock]{ close(sock); });
|
|
|
|
sockaddr_un addr = session_addr(session);
|
|
|
|
return connect(sock, (sockaddr*)&addr, sizeof(addr.sun_path)) != -1;
|
|
|
|
}
|
|
|
|
|
2018-03-22 21:36:18 +01:00
|
|
|
RemoteClient::RemoteClient(StringView session, StringView name, std::unique_ptr<UserInterface>&& ui,
|
2017-08-28 08:12:15 +02:00
|
|
|
int pid, const EnvVarMap& env_vars, StringView init_command,
|
2020-05-10 07:21:49 +02:00
|
|
|
Optional<BufferCoord> init_coord, Optional<int> stdin_fd)
|
2015-08-23 16:18:18 +02:00
|
|
|
: m_ui(std::move(ui))
|
2014-11-06 14:54:18 +01:00
|
|
|
{
|
|
|
|
int sock = connect_to(session);
|
2014-04-07 22:25:44 +02:00
|
|
|
|
2014-11-05 14:57:12 +01:00
|
|
|
{
|
2016-12-01 21:11:09 +01:00
|
|
|
MsgWriter msg{m_send_buffer, MessageType::Connect};
|
2019-05-22 20:03:49 +02:00
|
|
|
msg.write(pid, name, init_command, init_coord, m_ui->dimensions(), env_vars);
|
2014-11-05 14:57:12 +01:00
|
|
|
}
|
2020-05-10 07:21:49 +02:00
|
|
|
send_data(sock, m_send_buffer, stdin_fd);
|
2013-01-11 19:17:21 +01:00
|
|
|
|
2016-11-29 22:35:53 +01:00
|
|
|
m_ui->set_on_key([this](Key key){
|
2016-12-01 21:11:09 +01:00
|
|
|
MsgWriter msg(m_send_buffer, MessageType::Key);
|
2016-11-29 22:35:53 +01:00
|
|
|
msg.write(key);
|
2016-12-01 21:11:09 +01:00
|
|
|
m_socket_watcher->events() |= FdEvents::Write;
|
2016-11-29 22:35:53 +01:00
|
|
|
});
|
2014-11-05 14:57:12 +01:00
|
|
|
|
2021-03-10 23:02:02 +01:00
|
|
|
m_socket_watcher.reset(new FDWatcher{sock, FdEvents::Read | FdEvents::Write, EventMode::Urgent,
|
2018-09-07 01:08:04 +02:00
|
|
|
[this, reader = MsgReader{}](FDWatcher& watcher, FdEvents events, EventMode) mutable {
|
2016-08-31 20:33:02 +02:00
|
|
|
const int sock = watcher.fd();
|
2016-12-01 21:11:09 +01:00
|
|
|
if (events & FdEvents::Write and send_data(sock, m_send_buffer))
|
2018-09-07 01:08:04 +02:00
|
|
|
watcher.events() &= ~FdEvents::Write;
|
2016-12-01 21:11:09 +01:00
|
|
|
|
|
|
|
while (events & FdEvents::Read and
|
|
|
|
not reader.ready() and fd_readable(sock))
|
|
|
|
{
|
2016-08-31 20:33:02 +02:00
|
|
|
reader.read_available(sock);
|
2012-10-25 12:51:01 +02:00
|
|
|
|
2016-12-01 21:11:09 +01:00
|
|
|
if (not reader.ready())
|
|
|
|
continue;
|
2014-04-15 20:08:47 +02:00
|
|
|
|
2016-12-01 21:11:09 +01:00
|
|
|
auto clear_reader = on_scope_end([&reader] { reader.reset(); });
|
|
|
|
switch (reader.type())
|
|
|
|
{
|
|
|
|
case MessageType::MenuShow:
|
|
|
|
{
|
2019-04-20 18:43:52 +02:00
|
|
|
auto choices = reader.read<Vector<DisplayLine>>();
|
2016-12-01 21:11:09 +01:00
|
|
|
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:
|
|
|
|
{
|
2019-11-22 11:48:26 +01:00
|
|
|
auto title = reader.read<DisplayLine>();
|
|
|
|
auto content = reader.read<DisplayLineList>();
|
2016-12-01 21:11:09 +01:00
|
|
|
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;
|
|
|
|
}
|
2017-04-12 11:39:17 +02:00
|
|
|
case MessageType::SetCursor:
|
|
|
|
{
|
|
|
|
auto mode = reader.read<CursorMode>();
|
|
|
|
auto coord = reader.read<DisplayCoord>();
|
|
|
|
m_ui->set_cursor(mode, coord);
|
|
|
|
break;
|
|
|
|
}
|
2016-12-01 21:11:09 +01:00
|
|
|
case MessageType::Refresh:
|
|
|
|
m_ui->refresh(reader.read<bool>());
|
|
|
|
break;
|
|
|
|
case MessageType::SetOptions:
|
2019-04-20 18:43:52 +02:00
|
|
|
m_ui->set_ui_options(reader.read<HashMap<String, String, MemoryDomain::Options>>());
|
2016-12-01 21:11:09 +01:00
|
|
|
break;
|
2017-08-23 08:22:23 +02:00
|
|
|
case MessageType::Exit:
|
|
|
|
m_exit_status = reader.read<int>();
|
2018-09-07 01:08:04 +02:00
|
|
|
watcher.close_fd();
|
|
|
|
return;
|
2016-12-01 21:11:09 +01:00
|
|
|
default:
|
|
|
|
kak_assert(false);
|
|
|
|
}
|
2016-08-31 20:33:02 +02:00
|
|
|
}
|
|
|
|
}});
|
2012-10-23 22:55:44 +02:00
|
|
|
}
|
|
|
|
|
2018-05-23 00:14:56 +02:00
|
|
|
bool RemoteClient::is_ui_ok() const
|
|
|
|
{
|
|
|
|
return m_ui->is_ok();
|
|
|
|
}
|
|
|
|
|
2014-10-20 20:18:38 +02:00
|
|
|
void send_command(StringView session, StringView command)
|
2014-03-02 03:01:09 +01:00
|
|
|
{
|
2014-11-06 14:54:18 +01:00
|
|
|
int sock = connect_to(session);
|
2016-08-09 22:45:06 +02:00
|
|
|
auto close_sock = on_scope_end([sock]{ close(sock); });
|
2016-12-01 21:11:09 +01:00
|
|
|
RemoteBuffer buffer;
|
|
|
|
{
|
|
|
|
MsgWriter msg{buffer, MessageType::Command};
|
|
|
|
msg.write(command);
|
|
|
|
}
|
|
|
|
write(sock, {buffer.data(), buffer.data() + buffer.size()});
|
2014-03-02 03:01:09 +01:00
|
|
|
}
|
|
|
|
|
2013-03-12 18:53:18 +01:00
|
|
|
|
2013-03-13 19:59:39 +01:00
|
|
|
// 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.
|
2014-03-25 10:21:20 +01:00
|
|
|
class Server::Accepter
|
2012-12-18 21:20:36 +01:00
|
|
|
{
|
2013-03-13 19:59:39 +01:00
|
|
|
public:
|
2014-03-25 10:21:20 +01:00
|
|
|
Accepter(int socket)
|
2021-03-10 23:02:02 +01:00
|
|
|
: m_socket_watcher(socket, FdEvents::Read, EventMode::Urgent,
|
2016-11-30 14:59:08 +01:00
|
|
|
[this](FDWatcher&, FdEvents, EventMode mode) {
|
2018-11-26 02:47:44 +01:00
|
|
|
handle_available_input(mode);
|
2014-11-25 02:00:18 +01:00
|
|
|
})
|
2014-04-05 13:04:37 +02:00
|
|
|
{}
|
2013-03-13 19:59:39 +01:00
|
|
|
|
|
|
|
private:
|
2018-11-26 02:47:44 +01:00
|
|
|
void handle_available_input(EventMode mode)
|
2013-03-12 18:53:18 +01:00
|
|
|
{
|
2016-08-31 10:24:07 +02:00
|
|
|
const int sock = m_socket_watcher.fd();
|
2016-09-05 14:47:56 +02:00
|
|
|
try
|
2016-08-31 20:33:02 +02:00
|
|
|
{
|
2016-12-01 21:11:09 +01:00
|
|
|
while (not m_reader.ready() and fd_readable(sock))
|
2016-09-05 14:47:56 +02:00
|
|
|
m_reader.read_available(sock);
|
2016-08-31 20:33:02 +02:00
|
|
|
|
2018-11-26 02:47:44 +01:00
|
|
|
if (mode != EventMode::Normal or not m_reader.ready())
|
2016-09-05 14:47:56 +02:00
|
|
|
return;
|
2016-08-31 20:33:02 +02:00
|
|
|
|
2016-09-05 14:47:56 +02:00
|
|
|
switch (m_reader.type())
|
|
|
|
{
|
2016-08-31 10:24:07 +02:00
|
|
|
case MessageType::Connect:
|
2013-03-12 18:53:18 +01:00
|
|
|
{
|
2017-08-28 08:12:15 +02:00
|
|
|
auto pid = m_reader.read<int>();
|
2018-03-22 21:36:18 +01:00
|
|
|
auto name = m_reader.read<String>();
|
2016-12-01 21:40:50 +01:00
|
|
|
auto init_cmds = m_reader.read<String>();
|
2019-04-20 18:43:52 +02:00
|
|
|
auto init_coord = m_reader.read<Optional<BufferCoord>>();
|
2016-09-22 21:36:26 +02:00
|
|
|
auto dimensions = m_reader.read<DisplayCoord>();
|
2019-04-20 18:43:52 +02:00
|
|
|
auto env_vars = m_reader.read<HashMap<String, String, MemoryDomain::EnvVars>>();
|
2020-05-10 07:21:49 +02:00
|
|
|
|
|
|
|
if (auto stdin_fd = m_reader.ancillary_fd())
|
|
|
|
create_fifo_buffer(generate_buffer_name("*stdin-{}*"), *stdin_fd, Buffer::Flags::None);
|
|
|
|
|
2017-01-08 23:30:15 +01:00
|
|
|
auto* ui = new RemoteUI{sock, dimensions};
|
2018-04-29 14:27:28 +02:00
|
|
|
ClientManager::instance().create_client(
|
|
|
|
std::unique_ptr<UserInterface>(ui), pid, std::move(name),
|
|
|
|
std::move(env_vars), init_cmds, init_coord,
|
|
|
|
[ui](int status) { ui->exit(status); });
|
2016-09-04 18:54:07 +02:00
|
|
|
|
2016-08-31 10:24:07 +02:00
|
|
|
Server::instance().remove_accepter(this);
|
2016-09-05 14:47:56 +02:00
|
|
|
break;
|
2016-08-31 10:24:07 +02:00
|
|
|
}
|
|
|
|
case MessageType::Command:
|
|
|
|
{
|
2016-08-31 20:33:02 +02:00
|
|
|
auto command = m_reader.read<String>();
|
2016-08-31 10:24:07 +02:00
|
|
|
if (not command.empty()) try
|
2013-03-13 19:59:39 +01:00
|
|
|
{
|
2015-04-19 19:47:52 +02:00
|
|
|
Context context{Context::EmptyContextFlag{}};
|
2016-08-31 10:24:07 +02:00
|
|
|
CommandManager::instance().execute(command, context);
|
2013-03-13 19:59:39 +01:00
|
|
|
}
|
2016-09-05 14:47:56 +02:00
|
|
|
catch (const runtime_error& e)
|
2013-03-13 19:59:39 +01:00
|
|
|
{
|
2015-06-06 12:54:48 +02:00
|
|
|
write_to_debug_buffer(format("error running command '{}': {}",
|
2016-08-31 10:24:07 +02:00
|
|
|
command, e.what()));
|
2013-03-13 19:59:39 +01:00
|
|
|
}
|
2016-08-31 10:24:07 +02:00
|
|
|
close(sock);
|
2014-03-25 10:21:20 +01:00
|
|
|
Server::instance().remove_accepter(this);
|
2016-09-05 14:47:56 +02:00
|
|
|
break;
|
2013-03-12 18:53:18 +01:00
|
|
|
}
|
2016-08-31 10:24:07 +02:00
|
|
|
default:
|
2018-04-06 16:56:53 +02:00
|
|
|
write_to_debug_buffer("invalid introduction message received");
|
2016-08-31 10:24:07 +02:00
|
|
|
close(sock);
|
2014-03-25 10:21:20 +01:00
|
|
|
Server::instance().remove_accepter(this);
|
2016-09-05 14:47:56 +02:00
|
|
|
}
|
|
|
|
}
|
2016-12-20 11:34:48 +01:00
|
|
|
catch (const disconnected& err)
|
2016-09-05 14:47:56 +02:00
|
|
|
{
|
|
|
|
write_to_debug_buffer(format("accepting connection failed: {}", err.what()));
|
|
|
|
close(sock);
|
|
|
|
Server::instance().remove_accepter(this);
|
2013-03-13 19:59:39 +01:00
|
|
|
}
|
2013-03-12 18:53:18 +01:00
|
|
|
}
|
2013-03-13 19:59:39 +01:00
|
|
|
|
|
|
|
FDWatcher m_socket_watcher;
|
2016-08-31 20:33:02 +02:00
|
|
|
MsgReader m_reader;
|
2013-03-13 19:59:39 +01:00
|
|
|
};
|
|
|
|
|
2020-10-19 11:39:25 +02:00
|
|
|
Server::Server(String session_name, bool is_daemon)
|
|
|
|
: m_session{std::move(session_name)}, m_is_daemon{is_daemon}
|
2013-03-13 19:59:39 +01:00
|
|
|
{
|
|
|
|
int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
fcntl(listen_sock, F_SETFD, FD_CLOEXEC);
|
2014-11-06 14:54:18 +01:00
|
|
|
sockaddr_un addr = session_addr(m_session);
|
2013-03-13 19:59:39 +01:00
|
|
|
|
2021-05-01 07:29:50 +02:00
|
|
|
make_directory(session_directory(), 0711);
|
2016-12-16 00:47:34 +01:00
|
|
|
|
|
|
|
// Do not give any access to the socket to other users by default
|
|
|
|
auto old_mask = umask(0077);
|
|
|
|
auto restore_mask = on_scope_end([old_mask]() { umask(old_mask); });
|
2015-08-23 15:13:46 +02:00
|
|
|
|
2013-03-13 19:59:39 +01:00
|
|
|
if (bind(listen_sock, (sockaddr*) &addr, sizeof(sockaddr_un)) == -1)
|
2016-12-17 06:46:04 +01:00
|
|
|
throw runtime_error(format("unable to bind listen socket '{}': {}",
|
|
|
|
addr.sun_path, strerror(errno)));
|
2013-03-13 19:59:39 +01:00
|
|
|
|
|
|
|
if (listen(listen_sock, 4) == -1)
|
2016-12-17 06:46:04 +01:00
|
|
|
throw runtime_error(format("unable to listen on socket '{}': {}",
|
|
|
|
addr.sun_path, strerror(errno)));
|
2013-03-13 19:59:39 +01:00
|
|
|
|
2018-05-17 14:55:53 +02:00
|
|
|
auto accepter = [this](FDWatcher& watcher, FdEvents, EventMode) {
|
2013-03-13 19:59:39 +01:00
|
|
|
sockaddr_un client_addr;
|
|
|
|
socklen_t client_addr_len = sizeof(sockaddr_un);
|
2014-04-05 13:04:37 +02:00
|
|
|
int sock = accept(watcher.fd(), (sockaddr*) &client_addr,
|
|
|
|
&client_addr_len);
|
2013-03-13 19:59:39 +01:00
|
|
|
if (sock == -1)
|
|
|
|
throw runtime_error("accept failed");
|
|
|
|
fcntl(sock, F_SETFD, FD_CLOEXEC);
|
|
|
|
|
2014-03-25 10:21:20 +01:00
|
|
|
m_accepters.emplace_back(new Accepter{sock});
|
2013-03-13 19:59:39 +01:00
|
|
|
};
|
2021-03-10 23:02:02 +01:00
|
|
|
m_listener.reset(new FDWatcher{listen_sock, FdEvents::Read, EventMode::Urgent, accepter});
|
2013-03-13 19:59:39 +01:00
|
|
|
}
|
|
|
|
|
2016-07-28 01:16:41 +02:00
|
|
|
bool Server::rename_session(StringView name)
|
2016-07-20 16:52:53 +02:00
|
|
|
{
|
2019-07-29 19:38:11 +02:00
|
|
|
String old_socket_file = session_path(m_session);
|
|
|
|
String new_socket_file = session_path(name);
|
2016-07-20 16:52:53 +02:00
|
|
|
|
2019-06-06 09:37:57 +02:00
|
|
|
if (file_exists(new_socket_file))
|
|
|
|
return false;
|
|
|
|
|
2016-07-28 01:16:41 +02:00
|
|
|
if (rename(old_socket_file.c_str(), new_socket_file.c_str()) != 0)
|
2016-07-20 16:52:53 +02:00
|
|
|
return false;
|
|
|
|
|
2016-07-28 01:16:41 +02:00
|
|
|
m_session = name.str();
|
2016-07-20 16:52:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-10-08 21:05:47 +02:00
|
|
|
void Server::close_session(bool do_unlink)
|
2013-03-13 19:59:39 +01:00
|
|
|
{
|
2015-10-08 21:05:47 +02:00
|
|
|
if (do_unlink)
|
|
|
|
{
|
2019-07-29 19:38:11 +02:00
|
|
|
String socket_file = session_path(m_session);
|
2016-07-20 16:52:53 +02:00
|
|
|
unlink(socket_file.c_str());
|
2015-10-08 21:05:47 +02:00
|
|
|
}
|
2014-12-03 14:56:02 +01:00
|
|
|
m_listener->close_fd();
|
2014-01-27 20:53:17 +01:00
|
|
|
m_listener.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
Server::~Server()
|
|
|
|
{
|
2015-08-22 12:27:48 +02:00
|
|
|
if (m_listener)
|
|
|
|
close_session();
|
2012-12-18 21:20:36 +01:00
|
|
|
}
|
|
|
|
|
2014-03-25 10:21:20 +01:00
|
|
|
void Server::remove_accepter(Accepter* accepter)
|
|
|
|
{
|
|
|
|
auto it = find(m_accepters, accepter);
|
|
|
|
kak_assert(it != m_accepters.end());
|
|
|
|
m_accepters.erase(it);
|
|
|
|
}
|
|
|
|
|
2012-10-23 22:55:44 +02:00
|
|
|
}
|