Skip to content

Commit

Permalink
directvt#571 WIP: TCP connection for X11
Browse files Browse the repository at this point in the history
  • Loading branch information
o-sdn-o committed Aug 22, 2024
1 parent 997fc72 commit c8e011e
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 62 deletions.
128 changes: 71 additions & 57 deletions src/netxs/desktopio/directvt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,78 @@ namespace netxs::directvt
};
#pragma pack(pop)

template<class T>
void fuse_ext(auto& block, T&& data)
{
using D = std::remove_cv_t<std::remove_reference_t<T>>;
if constexpr (std::is_same_v<D, char>
|| std::is_same_v<D, byte>
|| std::is_same_v<D, type>)
{
block.text::push_back((char)data);
}
else if constexpr (std::is_arithmetic_v<D>
|| std::is_same_v<D, twod>
|| std::is_same_v<D, fp2d>
|| std::is_same_v<D, dent>
|| std::is_same_v<D, rect>)
{
auto le_data = netxs::letoh(data);
block += view{ (char*)&le_data, sizeof(le_data) };
}
else if constexpr (std::is_same_v<D, argb>)
{
block += view{ (char*)&data, sizeof(data) };
}
else if constexpr (std::is_same_v<D, view>
|| std::is_same_v<D, qiew>
|| std::is_same_v<D, text>)
{
auto length = (sz_t)data.length();
auto le_len = netxs::letoh(length);
block += view{ (char*)&le_len, sizeof(le_len) };
block += data;
}
else if constexpr (std::is_same_v<D, time>)
{
auto n = data.time_since_epoch().count();
auto le_n = netxs::letoh(n);
block += view{ (char*)&le_n, sizeof(le_n) };
}
else if constexpr (std::is_same_v<D, std::unordered_map<text, text>>
|| std::is_same_v<D, std::map<text, text>>
|| std::is_same_v<D, generics::imap<text, text>>)
{
//todo implement
}
else if constexpr (std::is_same_v<D, noop>)
{
// Noop.
}
else if constexpr (requires{ std::begin(std::declval<D>()); })
{
auto length = (sz_t)data.size();
auto le_len = netxs::letoh(length);
block += view{ (char*)&le_len, sizeof(le_len) };
for (auto& item : data) fuse_ext(block, item);
}
else log(prompt::dtvt, "Unsupported data type");
}

struct packet : text
{
void fuse(auto&& data) { fuse_ext(*this, std::forward<decltype(data)>(data)); }
auto& add(auto&& data) { fuse(std::forward<decltype(data)>(data)); return *this; }
auto& add(auto* data, auto size) { operator+=(view{ data, size }); return *this; }
auto& add(auto&& data, auto&&... data_list)
{
fuse(std::forward<decltype(data)>(data));
return add(std::forward<decltype(data_list)>(data_list)...);
}
};

struct stream
{
//todo revise
type next{};

constexpr explicit operator bool () const
Expand All @@ -137,62 +206,7 @@ namespace netxs::directvt

// stream: .
template<class T>
inline void fuse(T&& data)
{
using D = std::remove_cv_t<std::remove_reference_t<T>>;
if constexpr (std::is_same_v<D, char>
|| std::is_same_v<D, byte>
|| std::is_same_v<D, type>)
{
block.text::push_back((char)data);
}
else if constexpr (std::is_arithmetic_v<D>
|| std::is_same_v<D, twod>
|| std::is_same_v<D, fp2d>
|| std::is_same_v<D, dent>
|| std::is_same_v<D, rect>)
{
auto le_data = netxs::letoh(data);
block += view{ (char*)&le_data, sizeof(le_data) };
}
else if constexpr (std::is_same_v<D, argb>)
{
block += view{ (char*)&data, sizeof(data) };
}
else if constexpr (std::is_same_v<D, view>
|| std::is_same_v<D, qiew>
|| std::is_same_v<D, text>)
{
auto length = (sz_t)data.length();
auto le_len = netxs::letoh(length);
block += view{ (char*)&le_len, sizeof(le_len) };
block += data;
}
else if constexpr (std::is_same_v<D, time>)
{
auto n = data.time_since_epoch().count();
auto le_n = netxs::letoh(n);
block += view{ (char*)&le_n, sizeof(le_n) };
}
else if constexpr (std::is_same_v<D, std::unordered_map<text, text>>
|| std::is_same_v<D, std::map<text, text>>
|| std::is_same_v<D, generics::imap<text, text>>)
{
//todo implement
}
else if constexpr (std::is_same_v<D, noop>)
{
// Noop.
}
else if constexpr (requires{ std::begin(std::declval<D>()); })
{
auto length = (sz_t)data.size();
auto le_len = netxs::letoh(length);
block += view{ (char*)&le_len, sizeof(le_len) };
for (auto& item : data) fuse(item);
}
else log(prompt::dtvt, "Unsupported data type");
}
void fuse(T&& data) { fuse_ext(block, std::forward<T>(data)); }
// stream: Replace bytes at specified position.
template<class T>
inline auto& add_at(sz_t at, T&& data)
Expand Down
1 change: 1 addition & 0 deletions src/netxs/desktopio/gui.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,7 @@ namespace netxs::gui
fp32 v_offset;
};
fonts& fcache;
font_face_ptr faceinst{};
std::vector<fp32> glyf_steps; // shaper: .
std::vector<glyph_offset> glyf_align; // shaper: .

Expand Down
137 changes: 134 additions & 3 deletions src/netxs/desktopio/system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <sys/types.h> // ::getaddrinfo
#include <sys/socket.h> // ::shutdown() ::socket(2)
#include <netdb.h> //
#include <arpa/inet.h> // ::inet_ntop()

#include <stdio.h>
#include <unistd.h> // ::read()
Expand Down Expand Up @@ -3439,6 +3440,129 @@ namespace netxs::os
}
return socket;
}

static auto open([[maybe_unused]] text addr, [[maybe_unused]] text port, [[maybe_unused]] bool logs = faux)
{
auto r = os::invalid_fd;
auto w = os::invalid_fd;
auto socket = sptr<ipc::stdcon>{};

#if defined(_WIN32)
// N/A
#else
auto addr_family = addr[0] == '/' ? AF_UNIX : AF_UNSPEC;
if (addr_family == AF_UNIX)
{
auto saddr = sockaddr_un{ .sun_family = AF_UNIX };
if (addr.size() > sizeof(sockaddr_un::sun_path) - 1) { if (logs) os::fail("Unix socket path too long"); }
else if ((w = ::socket(AF_UNIX, SOCK_STREAM, 0)) == os::invalid_fd) { if (logs) os::fail("Unix socket opening error"); }
else
{
r = w;
std::copy(addr.begin(), addr.end(), saddr.sun_path);
auto sock_addr_len = (socklen_t)(sizeof(saddr) - (sizeof(sockaddr_un::sun_path) - (addr.size() + 1)));
if (-1 == ::connect(r, (struct sockaddr*)&saddr, sock_addr_len))
{
if (logs) os::fail("Connection to '%path%' failed", addr);
os::close(r);
}
}
}
else
{
auto ipaddr_to_str = [](auto* ipaddr)
{
auto ip_addr = (sockaddr*)ipaddr;
auto family = ip_addr->sa_family;
auto addr = family == AF_INET ? (void*)&(((sockaddr_in*)ip_addr)->sin_addr)
: (void*)&(((sockaddr_in6*)ip_addr)->sin6_addr);
auto str = std::array<char, INET6_ADDRSTRLEN + 1>{}; // +1 for trailing null.
::inet_ntop(family, addr, str.data(), str.size() - 1);
return text{ str.data() };
};
auto str_to_ipaddrs = [](view str)
{
auto addrs = std::vector<sockaddr_in6>{};
if (str == "localhost")
{
addrs.push_back({ .sin6_family = AF_INET });
addrs.push_back({ .sin6_family = AF_INET6 });
((char*)&(addrs[0].sin6_flowinfo))[0] = 127; // [127.0.0.1]:0
((char*)&(addrs[0].sin6_flowinfo))[3] = 1; //
((char*)&(addrs[1].sin6_addr))[15] = 1; // [::1]:0
std::swap(addrs.front(), addrs.back());
}
else
{
auto& a = addrs.emplace_back();
str.find(':') != text::npos ? a.sin6_family = AF_INET6 : AF_INET;
auto rc = ::inet_pton(a.sin6_family, str.data(), &a.sin6_port);
if (rc != 1) addrs.pop_back();
}
return addrs;
};
// getaddrinfo() can't be statically linked.
//auto addrs = (addrinfo*)nullptr;
//auto hints = addrinfo{ .ai_family = AF_UNSPEC, // Allow IPv4 or IPv6.
// .ai_socktype = SOCK_STREAM }; // TCP connection only.
//if (ok(::getaddrinfo(addr.data(), port.data(), &hints, &addrs), "::getaddrinfo()", os::unexpected))
{
log("Host resolved to:");
//for (auto rec = addrs; rec; rec = rec->ai_next)
//{
// if (logs) log(" %addr%", ipaddr_to_str(rec->ai_addr));
//}
//for (auto rec = addrs; rec; rec = rec->ai_next)
//{
// auto ip_addr = sockaddr{ *(rec->ai_addr) };
// auto family = rec->ai_addr->sa_family;
// if (logs) log(" connect to '%path%:%port%'...", ipaddr_to_str(&ip_addr), port);
// auto s = ::socket(family, SOCK_STREAM, 0); // protocol=0: TCP is the default streaming socket for the IP protocol suite.
// if (s == os::invalid_fd) continue;
// auto addrlen = socklen_t(family == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6));
// if (::connect(s, &ip_addr, addrlen) != -1)
// {
// w = s;
// r = s;
// break; // Connected.
// }
// ::close(s);
//}
//::freeaddrinfo(addrs);
auto addrs = str_to_ipaddrs(addr);
for (auto& ip_addr : addrs)
{
if (logs) log(" %addr%", ipaddr_to_str(&ip_addr));
}
for (auto& ip_addr : addrs)
{
auto family = ip_addr.sin6_family;
if (logs) log(" connect to '[%path%]:%port%'...", ipaddr_to_str(&ip_addr), port);
auto s = ::socket(family, SOCK_STREAM, 0); // protocol=0: TCP is the default streaming socket for the IP protocol suite.
if (s == os::invalid_fd) continue;
auto addrlen = (socklen_t)(family == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6));
auto portval = utf::to_int(port, ui16{});
((byte*)&ip_addr.sin6_port)[0] = (byte)(portval >> 8);
((byte*)&ip_addr.sin6_port)[1] = (byte)(portval & 0xFF);
if (::connect(s, (sockaddr*)&ip_addr, addrlen) != -1)
{
w = s;
r = s;
break; // Connected.
}
::close(s);
}
if (logs && w == os::invalid_fd) os::fail("Connection to '[%path%]:%port%' failed", addr, port);
}
}
#endif

if (r != os::invalid_fd && w != os::invalid_fd)
{
socket = ptr::shared<ipc::stdcon>(r, w);
}
return socket;
}
};

auto stdio()
Expand Down Expand Up @@ -3657,13 +3781,20 @@ namespace netxs::os
os::stderr_fd = os::invalid_fd;
//if constexpr (!debugmode) ::FreeConsole();
::FreeConsole();
auto term = "Native GUI console";
log("%%Terminal type: %term%", prompt::os, term);
return;
}
// We are hosted by a shell.
#else
if (!haspty)
{
dtvt::vtmode |= ui::console::gui;
}
#endif
if (dtvt::vtmode & ui::console::gui)
{
auto term = "Native GUI console";
log("%%Terminal type: %term%", prompt::os, term);
return;
}
}

#if defined(_WIN32)
Expand Down
4 changes: 2 additions & 2 deletions src/netxs/desktopio/utf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -689,10 +689,10 @@ namespace netxs::utf
}
return std::nullopt;
}
template<class A = si32, si32 Base = 10, class T, class = std::enable_if_t<std::is_base_of_v<view, T>>>
template<class A = si32, si32 Base = 10, class T>
auto to_int(T&& utf8)
{
auto shadow = view{ std::forward<T>(utf8) };
auto shadow = view{ utf8 };
return to_int<A, Base>(shadow);
}
template<si32 Base = 10, class T, class A>
Expand Down

0 comments on commit c8e011e

Please sign in to comment.